aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/prov/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/prov/src/main')
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/DefaultJcaJceHelper.java95
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/JcaJceHelper.java59
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/JcaJceUtils.java53
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/NamedJcaJceHelper.java103
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/ProviderJcaJceHelper.java103
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/CipherInputStream.java217
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/CipherOutputStream.java147
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/MacOutputStream.java38
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DH.java41
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DSA.java70
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DSTU4145.java42
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/EC.java96
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ECGOST.java39
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ElGamal.java46
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/GOST.java49
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/IES.java23
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/RSA.java197
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/X509.java31
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java77
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java142
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java213
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java204
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/IESCipher.java507
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java227
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java128
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java119
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java103
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java132
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java167
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java171
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/DSASigner.java313
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java72
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java117
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java82
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java468
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java436
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java166
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java188
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java221
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/SignatureSpiLe.java69
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java462
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java456
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/IESCipher.java501
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java317
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java239
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java275
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java358
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java542
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java405
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java166
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java186
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java218
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParameterGeneratorSpi.java76
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParametersSpi.java131
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPrivateKey.java199
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPublicKey.java173
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java340
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/ElGamalUtil.java66
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/KeyFactorySpi.java156
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/KeyPairGeneratorSpi.java100
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/AlgorithmParameterGeneratorSpi.java65
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/AlgorithmParametersSpi.java138
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java253
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/BCGOST3410PublicKey.java224
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/KeyFactorySpi.java121
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/KeyPairGeneratorSpi.java81
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java229
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java138
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java363
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java265
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java241
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java139
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java172
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java586
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java366
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java142
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java162
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java78
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java394
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java66
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java216
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java78
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DHUtil.java50
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java112
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DSAEncoder.java13
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/EC5Util.java123
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java286
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java21
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/GOST3410Util.java52
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/IESUtil.java32
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/KeyUtil.java72
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java125
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java395
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java20
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/KeyFactory.java95
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/PEMUtil.java93
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java372
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java318
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java627
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java903
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java138
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ConfigurableProvider.java39
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/PKCS12StoreParameter.java51
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ProviderConfiguration.java12
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ProviderConfigurationPermission.java146
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/BCMessageDigest.java47
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/DigestAlgorithmProvider.java36
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/GOST3411.java94
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD2.java75
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD4.java75
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD5.java77
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD128.java75
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD160.java113
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD256.java75
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD320.java73
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA1.java200
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA224.java76
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA256.java96
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA3.java171
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA384.java89
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA512.java179
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SM3.java47
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Skein.java740
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Tiger.java115
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Whirlpool.java73
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/BC.java27
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/PKCS12.java30
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java1061
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java1778
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/AES.java640
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/ARC4.java124
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Blowfish.java75
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/CAST5.java221
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/CAST6.java90
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Camellia.java238
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/ChaCha.java51
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/DES.java505
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/DESede.java435
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/GOST28147.java157
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Grain128.java49
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Grainv1.java49
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/HC128.java49
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/HC256.java49
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/IDEA.java258
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Noekeon.java153
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/PBEPBKDF2.java228
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/PBEPKCS12.java120
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC2.java523
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC5.java177
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC6.java180
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Rijndael.java70
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SEED.java183
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Salsa20.java51
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Serpent.java103
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Shacal2.java124
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SipHash.java47
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Skipjack.java87
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java34
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/TEA.java62
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Threefish.java120
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Twofish.java132
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/VMPC.java65
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/VMPCKSA3.java51
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/XSalsa20.java51
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/XTEA.java62
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BCPBEKey.java155
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java19
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java29
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java1037
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java82
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseMac.java144
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java93
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java370
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java388
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BlockCipherProvider.java8
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java118
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/PBE.java319
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java68
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AlgorithmProvider.java8
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java42
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java17
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/DigestFactory.java131
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/SecretKeyUtil.java40
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/GOST28147ParameterSpec.java108
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/PBKDF2KeySpec.java23
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/RepeatedSecretKeySpec.java34
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/SkeinParameterSpec.java283
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECGOST3410NamedCurveTable.java61
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECKeyUtil.java229
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECNamedCurveTable.java60
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECPointUtil.java56
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/MultiCertStoreParameters.java51
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PKCS10CertificationRequest.java640
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PKCS12Util.java126
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PrincipalUtil.java81
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509KeyUsage.java57
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509LDAPCertStoreParameters.java1258
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509Principal.java165
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/examples/PKCS12Example.java379
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertPathBuilderException.java29
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertPathValidatorException.java30
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertificateEncodingException.java21
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtException.java21
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtIOException.java21
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/BCKeyStore.java14
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECKey.java15
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPointEncoder.java20
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPrivateKey.java16
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPublicKey.java17
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalKey.java8
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalPrivateKey.java10
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalPublicKey.java10
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410Key.java11
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410Params.java15
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410PrivateKey.java9
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410PublicKey.java10
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/IESKey.java22
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/MQVPrivateKey.java27
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/MQVPublicKey.java20
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/PKCS12BagAttributeCarrier.java21
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/netscape/NetscapeCertRequest.java303
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/AnnotatedException.java32
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BouncyCastleProvider.java283
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java167
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenJCEBlockCipher.java621
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenKDF2BytesGenerator.java127
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenPBE.java441
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertPathValidatorUtilities.java1426
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertStatus.java46
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertStoreCollectionSpi.java104
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/DHUtil.java50
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/ExtCRLException.java20
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEDHPrivateKey.java188
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEDHPublicKey.java178
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEECPrivateKey.java478
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEECPublicKey.java525
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEElGamalPrivateKey.java167
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEElGamalPublicKey.java140
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPrivateCrtKey.java241
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPrivateKey.java146
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPublicKey.java131
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEStreamCipher.java613
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKDSAPrivateKey.java180
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKDSAPublicKey.java177
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKPKCS12StoreParameter.java51
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/MultiCertStoreSpi.java85
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PEMUtil.java94
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java303
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXAttrCertPathValidatorSpi.java99
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCRLUtil.java155
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java261
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java431
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXNameConstraintValidator.java1927
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXNameConstraintValidatorException.java10
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXPolicyNode.java168
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java2569
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java703
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/ReasonsMask.java101
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509AttrCertParser.java156
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLEntryObject.java318
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLObject.java625
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLParser.java150
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertPairParser.java77
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertParser.java158
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertificateObject.java901
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java477
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509SignatureUtil.java138
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreAttrCertCollection.java34
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCRLCollection.java34
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCertCollection.java34
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCertPairCollection.java64
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPAttrCerts.java79
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCRLs.java87
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCertPairs.java75
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCerts.java128
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECKeySpec.java26
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveGenParameterSpec.java28
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveParameterSpec.java62
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveSpec.java122
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECParameterSpec.java121
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECPrivateKeySpec.java35
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECPublicKeySpec.java42
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalGenParameterSpec.java28
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalKeySpec.java20
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalParameterSpec.java46
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalPrivateKeySpec.java33
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalPublicKeySpec.java33
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST28147ParameterSpec.java48
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410ParameterSpec.java133
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PrivateKeySpec.java70
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PublicKeyParameterSetSpec.java78
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PublicKeySpec.java78
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/IEKeySpec.java70
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/IESParameterSpec.java104
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/MQVPrivateKeySpec.java93
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/MQVPublicKeySpec.java68
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/RepeatedSecretKeySpec.java17
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/BasicOCSPResp.java366
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/BasicOCSPRespGenerator.java344
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/CertificateID.java170
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/CertificateStatus.java6
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPException.java32
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPReq.java417
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPReqGenerator.java294
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPResp.java128
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPRespGenerator.java60
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPRespStatus.java14
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPUtil.java198
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/Req.java108
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RespData.java142
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RespID.java80
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RevokedStatus.java63
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/SingleResp.java164
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/UnknownStatus.java12
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java157
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/McEliece.java62
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/Rainbow.java36
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java131
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java307
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java227
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java334
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java231
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java346
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java47
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java131
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java253
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java343
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java146
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java47
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java307
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java171
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java247
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java243
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java170
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java236
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java72
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeysToParams.java49
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java164
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java522
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricHybridCipher.java397
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/CipherSpiExt.java635
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/KeyUtil.java72
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/ECCKeyGenParameterSpec.java192
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSKeySpec.java29
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSPrivateKeySpec.java353
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSPublicKeySpec.java40
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2ParameterSpec.java63
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2PrivateKeySpec.java161
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2PublicKeySpec.java88
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McEliecePrivateKeySpec.java201
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McEliecePublicKeySpec.java91
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowParameterSpec.java123
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowPrivateKeySpec.java125
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowPublicKeySpec.java68
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/AttributeCertificateHolder.java420
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/AttributeCertificateIssuer.java208
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/CertPathReviewerException.java72
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtCertificateEncodingException.java20
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java210
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtendedPKIXParameters.java651
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/NoSuchParserException.java10
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/NoSuchStoreException.java10
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/PKIXAttrCertChecker.java56
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/PKIXCertPathReviewer.java2544
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Attribute.java79
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509AttributeCertStoreSelector.java484
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509AttributeCertificate.java101
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CRLStoreSelector.java330
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertPairStoreSelector.java155
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertStoreSelector.java87
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertificatePair.java167
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CollectionStoreParameters.java70
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Store.java82
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StoreParameters.java5
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StoreSpi.java12
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StreamParser.java161
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StreamParserSpi.java45
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Util.java412
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V1CertificateGenerator.java377
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2AttributeCertificate.java350
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java269
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2CRLGenerator.java451
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V3CertificateGenerator.java527
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/examples/AttrCertExample.java314
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/AuthorityKeyIdentifierStructure.java152
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/SubjectKeyIdentifierStructure.java53
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/X509ExtensionUtil.java101
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/LDAPStoreHelper.java1116
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/StreamParser.java10
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/StreamParsingException.java18
-rw-r--r--libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/examples/package.html5
-rw-r--r--libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/interfaces/package.html5
-rw-r--r--libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/package.html10
-rw-r--r--libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/spec/package.html5
-rw-r--r--libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/ocsp/package.html5
-rw-r--r--libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/examples/package.html7
-rw-r--r--libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/extension/package.html5
-rw-r--r--libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/package.html7
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/dsa/DSASigner.java280
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java221
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java230
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java368
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java143
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java129
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java397
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java379
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java107
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/MultiCertStoreParameters.java51
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/netscape/NetscapeCertRequest.java296
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/AnnotatedException.java29
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/BouncyCastleProvider.java274
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java108
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/CertStoreCollectionSpi.java104
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/MultiCertStoreSpi.java85
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java365
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java2182
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXPolicyNode.java167
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/ProviderUtil.java47
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java87
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/X509CRLObject.java554
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/X509CertificateObject.java856
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/ocsp/OCSPUtil.java198
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateHolder.java406
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateIssuer.java212
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509AttributeCertStoreSelector.java488
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509CRLStoreSelector.java26
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509CertStoreSelector.java26
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509Util.java397
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V1CertificateGenerator.java345
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java281
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2CRLGenerator.java435
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V3CertificateGenerator.java495
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.2/org/spongycastle/jce/exception/ExtCertPathBuilderException.java29
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.2/org/spongycastle/jce/exception/ExtCertPathValidatorException.java29
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/ProviderJcaJceHelper.java104
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java201
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java428
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java397
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java379
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java134
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java293
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java556
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java858
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java125
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java1624
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java1029
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java229
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java51
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java583
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java41
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java296
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java255
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java182
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java38
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java50
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java18
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java276
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java271
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java22
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java59
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java41
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java382
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java187
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java52
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java104
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java556
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java183
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java99
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java124
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java138
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java190
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java103
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java163
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java150
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java844
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java107
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java196
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java293
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java717
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java2468
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java12
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html5
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java29
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java30
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java1417
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java104
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java146
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java557
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java643
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKPKCS12KeyStore.java1586
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java85
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java155
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java395
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java431
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java169
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java72
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java2581
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java293
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java556
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java858
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java44
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/BasicOCSPResp.java366
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPReq.java415
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPReqGenerator.java292
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPUtil.java198
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/RespID.java80
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateHolder.java406
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateIssuer.java211
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java210
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXParameters.java647
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509AttributeCertStoreSelector.java486
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509CRLStoreSelector.java330
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509CertStoreSelector.java86
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509Util.java397
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V1CertificateGenerator.java341
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V2CRLGenerator.java432
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V3CertificateGenerator.java491
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/examples/AttrCertExample.java290
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java397
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java376
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java317
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java200
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java259
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java355
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java371
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java454
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java128
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java144
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java219
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java299
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java217
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java509
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java405
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java128
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java220
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java1624
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/interfaces/ECKey.java22
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java166
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/CertPathValidatorUtilities.java1439
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/JDKPKCS12KeyStore.java1565
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/X509SignatureUtil.java125
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/X509CRLStoreSelector.java330
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/X509CertStoreSelector.java86
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/util/LDAPStoreHelper.java1118
-rw-r--r--libraries/spongycastle/prov/src/main/resources/org/spongycastle/x509/CertPathReviewerMessages.properties616
-rw-r--r--libraries/spongycastle/prov/src/main/resources/org/spongycastle/x509/CertPathReviewerMessages_de.properties621
546 files changed, 131832 insertions, 0 deletions
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/DefaultJcaJceHelper.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/DefaultJcaJceHelper.java
new file mode 100644
index 000000000..ada25f694
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/DefaultJcaJceHelper.java
@@ -0,0 +1,95 @@
+package org.spongycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+public class DefaultJcaJceHelper
+ implements JcaJceHelper
+{
+ public Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException
+ {
+ return Cipher.getInstance(algorithm);
+ }
+
+ public Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Mac.getInstance(algorithm);
+ }
+
+ public KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyAgreement.getInstance(algorithm);
+ }
+
+ public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return AlgorithmParameterGenerator.getInstance(algorithm);
+ }
+
+ public AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return AlgorithmParameters.getInstance(algorithm);
+ }
+
+ public KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyGenerator.getInstance(algorithm);
+ }
+
+ public KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyFactory.getInstance(algorithm);
+ }
+
+ public SecretKeyFactory createSecretKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return SecretKeyFactory.getInstance(algorithm);
+ }
+
+ public KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyPairGenerator.getInstance(algorithm);
+ }
+
+ public MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return MessageDigest.getInstance(algorithm);
+ }
+
+ public Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm);
+ }
+
+ public CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, CertificateException
+ {
+ return CertificateFactory.getInstance(algorithm);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/JcaJceHelper.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/JcaJceHelper.java
new file mode 100644
index 000000000..88f129be0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/JcaJceHelper.java
@@ -0,0 +1,59 @@
+package org.spongycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+public interface JcaJceHelper
+{
+ Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
+
+ Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ SecretKeyFactory createSecretKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CertificateException;
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/JcaJceUtils.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/JcaJceUtils.java
new file mode 100644
index 000000000..8a9f202dd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/JcaJceUtils.java
@@ -0,0 +1,53 @@
+package org.spongycastle.jcajce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Primitive;
+
+public class JcaJceUtils
+{
+ private JcaJceUtils()
+ {
+
+ }
+
+ /**
+ * Extract an ASN.1 encodable from an AlgorithmParameters object.
+ *
+ * @param params the object to get the encoding used to create the return value.
+ * @return an ASN.1 object representing the primitives making up the params parameter.
+ * @throws IOException if an encoding cannot be extracted.
+ */
+ public static ASN1Encodable extractParameters(AlgorithmParameters params)
+ throws IOException
+ {
+ // we try ASN.1 explicitly first just in case and then role back to the default.
+ ASN1Encodable asn1Params;
+ try
+ {
+ asn1Params = ASN1Primitive.fromByteArray(params.getEncoded("ASN.1"));
+ }
+ catch (Exception ex)
+ {
+ asn1Params = ASN1Primitive.fromByteArray(params.getEncoded());
+ }
+
+ return asn1Params;
+ }
+
+ public static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
+ throws IOException
+ {
+ // we try ASN.1 explicitly first just in case and then role back to the default.
+ try
+ {
+ params.init(sParams.toASN1Primitive().getEncoded(), "ASN.1");
+ }
+ catch (Exception ex)
+ {
+ params.init(sParams.toASN1Primitive().getEncoded());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/NamedJcaJceHelper.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/NamedJcaJceHelper.java
new file mode 100644
index 000000000..117ca4ec1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/NamedJcaJceHelper.java
@@ -0,0 +1,103 @@
+package org.spongycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+public class NamedJcaJceHelper
+ implements JcaJceHelper
+{
+ protected final String providerName;
+
+ public NamedJcaJceHelper(String providerName)
+ {
+ this.providerName = providerName;
+ }
+
+ public Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException
+ {
+ return Cipher.getInstance(algorithm, providerName);
+ }
+
+ public Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Mac.getInstance(algorithm, providerName);
+ }
+
+ public KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyAgreement.getInstance(algorithm, providerName);
+ }
+
+ public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return AlgorithmParameterGenerator.getInstance(algorithm, providerName);
+ }
+
+ public AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return AlgorithmParameters.getInstance(algorithm, providerName);
+ }
+
+ public KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyGenerator.getInstance(algorithm, providerName);
+ }
+
+ public KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyFactory.getInstance(algorithm, providerName);
+ }
+
+ public SecretKeyFactory createSecretKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return SecretKeyFactory.getInstance(algorithm, providerName);
+ }
+
+ public KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyPairGenerator.getInstance(algorithm, providerName);
+ }
+
+ public MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return MessageDigest.getInstance(algorithm, providerName);
+ }
+
+ public Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Signature.getInstance(algorithm, providerName);
+ }
+
+ public CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException
+ {
+ return CertificateFactory.getInstance(algorithm, providerName);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/ProviderJcaJceHelper.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/ProviderJcaJceHelper.java
new file mode 100644
index 000000000..e4cca6f78
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/ProviderJcaJceHelper.java
@@ -0,0 +1,103 @@
+package org.spongycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+public class ProviderJcaJceHelper
+ implements JcaJceHelper
+{
+ protected final Provider provider;
+
+ public ProviderJcaJceHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ public Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException
+ {
+ return Cipher.getInstance(algorithm, provider);
+ }
+
+ public Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Mac.getInstance(algorithm, provider);
+ }
+
+ public KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyAgreement.getInstance(algorithm, provider);
+ }
+
+ public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return AlgorithmParameterGenerator.getInstance(algorithm, provider);
+ }
+
+ public AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return AlgorithmParameters.getInstance(algorithm, provider);
+ }
+
+ public KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyGenerator.getInstance(algorithm, provider);
+ }
+
+ public KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyFactory.getInstance(algorithm, provider);
+ }
+
+ public SecretKeyFactory createSecretKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return SecretKeyFactory.getInstance(algorithm, provider);
+ }
+
+ public KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyPairGenerator.getInstance(algorithm, provider);
+ }
+
+ public MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return MessageDigest.getInstance(algorithm, provider);
+ }
+
+ public Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm, provider);
+ }
+
+ public CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, CertificateException
+ {
+ return CertificateFactory.getInstance(algorithm, provider);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/CipherInputStream.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/CipherInputStream.java
new file mode 100644
index 000000000..e3254dc5e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/CipherInputStream.java
@@ -0,0 +1,217 @@
+package org.spongycastle.jcajce.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.crypto.io.InvalidCipherTextIOException;
+
+/**
+ * A CipherInputStream is composed of an InputStream and a cipher so that read() methods return data
+ * that are read in from the underlying InputStream but have been additionally processed by the
+ * Cipher. The cipher must be fully initialized before being used by a CipherInputStream.
+ * <p/>
+ * For example, if the Cipher is initialized for decryption, the CipherInputStream will attempt to
+ * read in data and decrypt them, before returning the decrypted data.
+ * <p/>
+ * This is a reimplementation of {@link javax.crypto.CipherInputStream} that is safe for use with
+ * AEAD block ciphers, and does not silently catch {@link BadPaddingException} and
+ * {@link IllegalBlockSizeException} errors. Any errors that occur during {@link Cipher#doFinal()
+ * finalisation} are rethrown wrapped in an {@link InvalidCipherTextIOException}.
+ */
+public class CipherInputStream
+ extends FilterInputStream
+{
+ private final Cipher cipher;
+ private final byte[] inputBuffer = new byte[512];
+ private boolean finalized = false;
+ private byte[] buf;
+ private int maxBuf;
+ private int bufOff;
+
+ /**
+ * Constructs a CipherInputStream from an InputStream and an initialised Cipher.
+ */
+ public CipherInputStream(InputStream input, Cipher cipher)
+ {
+ super(input);
+ this.cipher = cipher;
+ }
+
+ /**
+ * Read data from underlying stream and process with cipher until end of stream or some data is
+ * available after cipher processing.
+ *
+ * @return -1 to indicate end of stream, or the number of bytes (> 0) available.
+ */
+ private int nextChunk()
+ throws IOException
+ {
+ if (finalized)
+ {
+ return -1;
+ }
+
+ bufOff = 0;
+ maxBuf = 0;
+
+ // Keep reading until EOF or cipher processing produces data
+ while (maxBuf == 0)
+ {
+ int read = in.read(inputBuffer);
+ if (read == -1)
+ {
+ buf = finaliseCipher();
+ if ((buf == null) || (buf.length == 0))
+ {
+ return -1;
+ }
+ maxBuf = buf.length;
+ return maxBuf;
+ }
+
+ buf = cipher.update(inputBuffer, 0, read);
+ if (buf != null)
+ {
+ maxBuf = buf.length;
+ }
+ }
+ return maxBuf;
+ }
+
+ private byte[] finaliseCipher()
+ throws InvalidCipherTextIOException
+ {
+ try
+ {
+ finalized = true;
+ return cipher.doFinal();
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new InvalidCipherTextIOException("Error finalising cipher", e);
+ }
+ }
+
+ /**
+ * Reads data from the underlying stream and processes it with the cipher until the cipher
+ * outputs data, and returns the next available byte.
+ * <p/>
+ * If the underlying stream is exhausted by this call, the cipher will be finalised.
+ *
+ * @throws IOException if there was an error closing the input stream.
+ * @throws InvalidCipherTextIOException if the data read from the stream was invalid ciphertext
+ * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails).
+ */
+ public int read()
+ throws IOException
+ {
+ if (bufOff >= maxBuf)
+ {
+ if (nextChunk() < 0)
+ {
+ return -1;
+ }
+ }
+
+ return buf[bufOff++] & 0xff;
+ }
+
+ /**
+ * Reads data from the underlying stream and processes it with the cipher until the cipher
+ * outputs data, and then returns up to <code>len</code> bytes in the provided array.
+ * <p/>
+ * If the underlying stream is exhausted by this call, the cipher will be finalised.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off the start offset in the destination array <code>b</code>
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or <code>-1</code> if there is no
+ * more data because the end of the stream has been reached.
+ * @throws IOException if there was an error closing the input stream.
+ * @throws InvalidCipherTextIOException if the data read from the stream was invalid ciphertext
+ * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails).
+ */
+ public int read(byte[] b, int off, int len)
+ throws IOException
+ {
+ if (bufOff >= maxBuf)
+ {
+ if (nextChunk() < 0)
+ {
+ return -1;
+ }
+ }
+
+ int toSupply = Math.min(len, available());
+ System.arraycopy(buf, bufOff, b, off, toSupply);
+ bufOff += toSupply;
+ return toSupply;
+ }
+
+ public long skip(long n)
+ throws IOException
+ {
+ if (n <= 0)
+ {
+ return 0;
+ }
+
+ int skip = (int)Math.min(n, available());
+ bufOff += skip;
+ return skip;
+ }
+
+ public int available()
+ throws IOException
+ {
+ return maxBuf - bufOff;
+ }
+
+ /**
+ * Closes the underlying input stream, and then finalises the processing of the data by the
+ * cipher.
+ *
+ * @throws IOException if there was an error closing the input stream.
+ * @throws InvalidCipherTextIOException if the data read from the stream was invalid ciphertext
+ * (e.g. the cipher is an AEAD cipher and the ciphertext tag check fails).
+ */
+ public void close()
+ throws IOException
+ {
+ try
+ {
+ in.close();
+ }
+ finally
+ {
+ if (!finalized)
+ {
+ // Reset the cipher, discarding any data buffered in it
+ // Errors in cipher finalisation trump I/O error closing input
+ finaliseCipher();
+ }
+ }
+ maxBuf = bufOff = 0;
+ }
+
+ public void mark(int readlimit)
+ {
+ }
+
+ public void reset()
+ throws IOException
+ {
+ }
+
+ public boolean markSupported()
+ {
+ return false;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/CipherOutputStream.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/CipherOutputStream.java
new file mode 100644
index 000000000..1139135ce
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/CipherOutputStream.java
@@ -0,0 +1,147 @@
+package org.spongycastle.jcajce.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.crypto.io.InvalidCipherTextIOException;
+
+/**
+ * A CipherOutputStream is composed of an OutputStream and a cipher so that write() methods process
+ * the written data with the cipher, and the output of the cipher is in turn written to the
+ * underlying OutputStream. The cipher must be fully initialized before being used by a
+ * CipherInputStream.
+ * <p/>
+ * For example, if the cipher is initialized for encryption, the CipherOutputStream will encrypt the
+ * data before writing the encrypted data to the underlying stream.
+ * <p/>
+ * This is a reimplementation of {@link javax.crypto.CipherOutputStream} that is safe for use with
+ * AEAD block ciphers, and does not silently catch {@link BadPaddingException} and
+ * {@link IllegalBlockSizeException} errors. Any errors that occur during {@link Cipher#doFinal()
+ * finalisation} are rethrown wrapped in an {@link InvalidCipherTextIOException}.
+ */
+public class CipherOutputStream
+ extends FilterOutputStream
+{
+ private final Cipher cipher;
+ private final byte[] oneByte = new byte[1];
+
+ /**
+ * Constructs a CipherOutputStream from an OutputStream and a Cipher.
+ */
+ public CipherOutputStream(OutputStream output, Cipher cipher)
+ {
+ super(output);
+ this.cipher = cipher;
+ }
+
+ /**
+ * Writes the specified byte to this output stream.
+ *
+ * @param b the <code>byte</code>.
+ * @throws java.io.IOException if an I/O error occurs.
+ */
+ public void write(int b)
+ throws IOException
+ {
+ oneByte[0] = (byte)b;
+ write(oneByte, 0, 1);
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array starting at offset
+ * <code>off</code> to this output stream.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @throws java.io.IOException if an I/O error occurs.
+ */
+ public void write(byte[] b, int off, int len)
+ throws IOException
+ {
+ byte[] outData = cipher.update(b, off, len);
+ if (outData != null)
+ {
+ out.write(outData);
+ }
+ }
+
+ /**
+ * Flushes this output stream by forcing any buffered output bytes that have already been
+ * processed by the encapsulated cipher object to be written out.
+ * <p/>
+ * <p/>
+ * Any bytes buffered by the encapsulated cipher and waiting to be processed by it will not be
+ * written out. For example, if the encapsulated cipher is a block cipher, and the total number
+ * of bytes written using one of the <code>write</code> methods is less than the cipher's block
+ * size, no bytes will be written out.
+ *
+ * @throws java.io.IOException if an I/O error occurs.
+ */
+ public void flush()
+ throws IOException
+ {
+ out.flush();
+ }
+
+ /**
+ * Closes this output stream and releases any system resources associated with this stream.
+ * <p/>
+ * This method invokes the <code>doFinal</code> method of the encapsulated cipher object, which
+ * causes any bytes buffered by the encapsulated cipher to be processed. The result is written
+ * out by calling the <code>flush</code> method of this output stream.
+ * <p/>
+ * This method resets the encapsulated cipher object to its initial state and calls the
+ * <code>close</code> method of the underlying output stream.
+ *
+ * @throws java.io.IOException if an I/O error occurs.
+ * @throws InvalidCipherTextIOException if the data written to this stream was invalid
+ * ciphertext (e.g. the cipher is an AEAD cipher and the ciphertext tag check
+ * fails).
+ */
+ public void close()
+ throws IOException
+ {
+ IOException error = null;
+ try
+ {
+ byte[] outData = cipher.doFinal();
+ if (outData != null)
+ {
+ out.write(outData);
+ }
+ }
+ catch (GeneralSecurityException e)
+ {
+ error = new InvalidCipherTextIOException("Error during cipher finalisation", e);
+ }
+ catch (Exception e)
+ {
+ error = new IOException("Error closing stream: " + e);
+ }
+ try
+ {
+ flush();
+ out.close();
+ }
+ catch (IOException e)
+ {
+ // Invalid ciphertext takes precedence over close error
+ if (error == null)
+ {
+ error = e;
+ }
+ }
+ if (error != null)
+ {
+ throw error;
+ }
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/MacOutputStream.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/MacOutputStream.java
new file mode 100644
index 000000000..ea3d76d9d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/io/MacOutputStream.java
@@ -0,0 +1,38 @@
+package org.spongycastle.jcajce.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.crypto.Mac;
+
+public class MacOutputStream
+ extends OutputStream
+{
+ protected Mac mac;
+
+ public MacOutputStream(
+ Mac mac)
+ {
+ this.mac = mac;
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ mac.update((byte)b);
+ }
+
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ mac.update(b, off, len);
+ }
+
+ public byte[] getMac()
+ {
+ return mac.doFinal();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DH.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DH.java
new file mode 100644
index 000000000..86ee0eaaf
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DH.java
@@ -0,0 +1,41 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class DH
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".dh.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyPairGenerator.DH", PREFIX + "KeyPairGeneratorSpi");
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("KeyAgreement.DH", PREFIX + "KeyAgreementSpi");
+ provider.addAlgorithm("Alg.Alias.KeyAgreement.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("KeyFactory.DH", PREFIX + "KeyFactorySpi");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("AlgorithmParameters.DH", PREFIX + "AlgorithmParametersSpi");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.DH", PREFIX + "AlgorithmParameterGeneratorSpi");
+
+ provider.addAlgorithm("Cipher.DHIES", PREFIX + "IESCipher$IES");
+ provider.addAlgorithm("Cipher.DHIESwithAES", PREFIX + "IESCipher$IESwithAES");
+ provider.addAlgorithm("Cipher.DHIESWITHAES", PREFIX + "IESCipher$IESwithAES");
+ provider.addAlgorithm("Cipher.DHIESWITHDESEDE", PREFIX + "IESCipher$IESwithDESede");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DSA.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DSA.java
new file mode 100644
index 000000000..acceacd7e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DSA.java
@@ -0,0 +1,70 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.dsa.DSAUtil;
+import org.spongycastle.jcajce.provider.asymmetric.dsa.KeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class DSA
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".dsa.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.DSA", PREFIX + "AlgorithmParametersSpi");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.DSA", PREFIX + "AlgorithmParameterGeneratorSpi");
+
+ provider.addAlgorithm("KeyPairGenerator.DSA", PREFIX + "KeyPairGeneratorSpi");
+ provider.addAlgorithm("KeyFactory.DSA", PREFIX + "KeyFactorySpi");
+
+ provider.addAlgorithm("Signature.DSA", PREFIX + "DSASigner$stdDSA");
+ provider.addAlgorithm("Signature.NONEWITHDSA", PREFIX + "DSASigner$noneDSA");
+
+ provider.addAlgorithm("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA");
+
+ provider.addAlgorithm("Signature.DETDSA", PREFIX + "DSASigner$detDSA");
+ provider.addAlgorithm("Signature.SHA1WITHDETDSA", PREFIX + "DSASigner$detDSA");
+ provider.addAlgorithm("Signature.SHA224WITHDETDSA", PREFIX + "DSASigner$detDSA224");
+ provider.addAlgorithm("Signature.SHA256WITHDETDSA", PREFIX + "DSASigner$detDSA256");
+ provider.addAlgorithm("Signature.SHA384WITHDETDSA", PREFIX + "DSASigner$detDSA384");
+ provider.addAlgorithm("Signature.SHA512WITHDETDSA", PREFIX + "DSASigner$detDSA512");
+
+ addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
+ addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
+ addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
+ addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
+
+ provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "DSA");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1withDSA", "DSA");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "DSA");
+ provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "DSA");
+ provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "DSA");
+ provider.addAlgorithm("Alg.Alias.Signature.DSAwithSHA1", "DSA");
+ provider.addAlgorithm("Alg.Alias.Signature.DSAWITHSHA1", "DSA");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1WithDSA", "DSA");
+ provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "DSA");
+
+ provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "DSA");
+
+ AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+ for (int i = 0; i != DSAUtil.dsaOids.length; i++)
+ {
+ provider.addAlgorithm("Alg.Alias.Signature." + DSAUtil.dsaOids[i], "DSA");
+
+ registerOid(provider, DSAUtil.dsaOids[i], "DSA", keyFact);
+ registerOidAlgorithmParameters(provider, DSAUtil.dsaOids[i], "DSA");
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DSTU4145.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DSTU4145.java
new file mode 100644
index 000000000..5e82f2cad
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/DSTU4145.java
@@ -0,0 +1,42 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.asn1.ua.UAObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.dstu.KeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class DSTU4145
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".dstu.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.DSTU4145", PREFIX + "KeyFactorySpi");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.DSTU-4145-2002", "DSTU4145");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.DSTU4145-3410", "DSTU4145");
+
+ registerOid(provider, UAObjectIdentifiers.dstu4145le, "DSTU4145", new KeyFactorySpi());
+ registerOidAlgorithmParameters(provider, UAObjectIdentifiers.dstu4145le, "DSTU4145");
+ registerOid(provider, UAObjectIdentifiers.dstu4145be, "DSTU4145", new KeyFactorySpi());
+ registerOidAlgorithmParameters(provider, UAObjectIdentifiers.dstu4145be, "DSTU4145");
+
+ provider.addAlgorithm("KeyPairGenerator.DSTU4145", PREFIX + "KeyPairGeneratorSpi");
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator.DSTU-4145", "DSTU4145");
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator.DSTU-4145-2002", "DSTU4145");
+
+ provider.addAlgorithm("Signature.DSTU4145", PREFIX + "SignatureSpi");
+ provider.addAlgorithm("Alg.Alias.Signature.DSTU-4145", "DSTU4145");
+ provider.addAlgorithm("Alg.Alias.Signature.DSTU-4145-2002", "DSTU4145");
+
+ addSignatureAlgorithm(provider, "GOST3411", "DSTU4145LE", PREFIX + "SignatureSpiLe", UAObjectIdentifiers.dstu4145le);
+ addSignatureAlgorithm(provider, "GOST3411", "DSTU4145", PREFIX + "SignatureSpi", UAObjectIdentifiers.dstu4145be);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/EC.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/EC.java
new file mode 100644
index 000000000..ff043d15d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/EC.java
@@ -0,0 +1,96 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.asn1.eac.EACObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class EC
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".ec.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyAgreement.ECDH", PREFIX + "KeyAgreementSpi$DH");
+ provider.addAlgorithm("KeyAgreement.ECDHC", PREFIX + "KeyAgreementSpi$DHC");
+ provider.addAlgorithm("KeyAgreement.ECMQV", PREFIX + "KeyAgreementSpi$MQV");
+ provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDF");
+ provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF");
+
+ registerOid(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC", new KeyFactorySpi.EC());
+ // TODO Should this be an alias for ECDH?
+ registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
+ registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+
+ registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC");
+ // TODO Should this be an alias for ECDH?
+ registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC");
+ registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "EC");
+
+ provider.addAlgorithm("KeyFactory.EC", PREFIX + "KeyFactorySpi$EC");
+ provider.addAlgorithm("KeyFactory.ECDSA", PREFIX + "KeyFactorySpi$ECDSA");
+ provider.addAlgorithm("KeyFactory.ECDH", PREFIX + "KeyFactorySpi$ECDH");
+ provider.addAlgorithm("KeyFactory.ECDHC", PREFIX + "KeyFactorySpi$ECDHC");
+ provider.addAlgorithm("KeyFactory.ECMQV", PREFIX + "KeyFactorySpi$ECMQV");
+
+ provider.addAlgorithm("KeyPairGenerator.EC", PREFIX + "KeyPairGeneratorSpi$EC");
+ provider.addAlgorithm("KeyPairGenerator.ECDSA", PREFIX + "KeyPairGeneratorSpi$ECDSA");
+ provider.addAlgorithm("KeyPairGenerator.ECDH", PREFIX + "KeyPairGeneratorSpi$ECDH");
+ provider.addAlgorithm("KeyPairGenerator.ECDHC", PREFIX + "KeyPairGeneratorSpi$ECDHC");
+ provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH");
+ provider.addAlgorithm("KeyPairGenerator.ECMQV", PREFIX + "KeyPairGeneratorSpi$ECMQV");
+
+ provider.addAlgorithm("Cipher.ECIES", PREFIX + "IESCipher$ECIES");
+ provider.addAlgorithm("Cipher.ECIESwithAES", PREFIX + "IESCipher$ECIESwithAES");
+ provider.addAlgorithm("Cipher.ECIESWITHAES", PREFIX + "IESCipher$ECIESwithAES");
+ provider.addAlgorithm("Cipher.ECIESwithDESEDE", PREFIX + "IESCipher$ECIESwithDESede");
+ provider.addAlgorithm("Cipher.ECIESWITHDESEDE", PREFIX + "IESCipher$ECIESwithDESede");
+
+ provider.addAlgorithm("Signature.ECDSA", PREFIX + "SignatureSpi$ecDSA");
+ provider.addAlgorithm("Signature.NONEwithECDSA", PREFIX + "SignatureSpi$ecDSAnone");
+
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHECDSA", "ECDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.ECDSAWITHSHA1", "ECDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
+ provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+
+ provider.addAlgorithm("Signature.DETECDSA", PREFIX + "SignatureSpi$ecDetDSA");
+ provider.addAlgorithm("Signature.SHA1WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA");
+ provider.addAlgorithm("Signature.SHA224WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA224");
+ provider.addAlgorithm("Signature.SHA256WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA256");
+ provider.addAlgorithm("Signature.SHA384WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA384");
+ provider.addAlgorithm("Signature.SHA512WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA512");
+
+ addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ addSignatureAlgorithm(provider, "SHA256", "ECDSA", PREFIX + "SignatureSpi$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ addSignatureAlgorithm(provider, "SHA384", "ECDSA", PREFIX + "SignatureSpi$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ addSignatureAlgorithm(provider, "SHA512", "ECDSA", PREFIX + "SignatureSpi$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+
+ provider.addAlgorithm("Signature.SHA1WITHECNR", PREFIX + "SignatureSpi$ecNR");
+ provider.addAlgorithm("Signature.SHA224WITHECNR", PREFIX + "SignatureSpi$ecNR224");
+ provider.addAlgorithm("Signature.SHA256WITHECNR", PREFIX + "SignatureSpi$ecNR256");
+ provider.addAlgorithm("Signature.SHA384WITHECNR", PREFIX + "SignatureSpi$ecNR384");
+ provider.addAlgorithm("Signature.SHA512WITHECNR", PREFIX + "SignatureSpi$ecNR512");
+
+ addSignatureAlgorithm(provider, "SHA1", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+ addSignatureAlgorithm(provider, "SHA224", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+ addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+ addSignatureAlgorithm(provider, "SHA384", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA384", EACObjectIdentifiers.id_TA_ECDSA_SHA_384);
+ addSignatureAlgorithm(provider, "SHA512", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA512", EACObjectIdentifiers.id_TA_ECDSA_SHA_512);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ECGOST.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ECGOST.java
new file mode 100644
index 000000000..cefae1a24
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ECGOST.java
@@ -0,0 +1,39 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.ecgost.KeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class ECGOST
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".ecgost.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.ECGOST3410", PREFIX + "KeyFactorySpi");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
+
+ registerOid(provider, CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410", new KeyFactorySpi());
+ registerOidAlgorithmParameters(provider, CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
+
+ provider.addAlgorithm("KeyPairGenerator.ECGOST3410", PREFIX + "KeyPairGeneratorSpi");
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
+
+ provider.addAlgorithm("Signature.ECGOST3410", PREFIX + "SignatureSpi");
+ provider.addAlgorithm("Alg.Alias.Signature.ECGOST-3410", "ECGOST3410");
+ provider.addAlgorithm("Alg.Alias.Signature.GOST-3410-2001", "ECGOST3410");
+
+ addSignatureAlgorithm(provider, "GOST3411", "ECGOST3410", PREFIX + "SignatureSpi", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ElGamal.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ElGamal.java
new file mode 100644
index 000000000..e2f44880e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ElGamal.java
@@ -0,0 +1,46 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.elgamal.KeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class ElGamal
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".elgamal.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameterGenerator.ELGAMAL", PREFIX + "AlgorithmParameterGeneratorSpi");
+ provider.addAlgorithm("AlgorithmParameterGenerator.ElGamal", PREFIX + "AlgorithmParameterGeneratorSpi");
+ provider.addAlgorithm("AlgorithmParameters.ELGAMAL", PREFIX + "AlgorithmParametersSpi");
+ provider.addAlgorithm("AlgorithmParameters.ElGamal", PREFIX + "AlgorithmParametersSpi");
+
+ provider.addAlgorithm("Cipher.ELGAMAL", PREFIX + "CipherSpi$NoPadding");
+ provider.addAlgorithm("Cipher.ElGamal", PREFIX + "CipherSpi$NoPadding");
+ provider.addAlgorithm("Alg.Alias.Cipher.ELGAMAL/ECB/PKCS1PADDING", "ELGAMAL/PKCS1");
+ provider.addAlgorithm("Alg.Alias.Cipher.ELGAMAL/NONE/PKCS1PADDING", "ELGAMAL/PKCS1");
+ provider.addAlgorithm("Alg.Alias.Cipher.ELGAMAL/NONE/NOPADDING", "ELGAMAL");
+
+ provider.addAlgorithm("Cipher.ELGAMAL/PKCS1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+ provider.addAlgorithm("KeyFactory.ELGAMAL", PREFIX + "KeyFactorySpi");
+ provider.addAlgorithm("KeyFactory.ElGamal", PREFIX + "KeyFactorySpi");
+
+ provider.addAlgorithm("KeyPairGenerator.ELGAMAL", PREFIX + "KeyPairGeneratorSpi");
+ provider.addAlgorithm("KeyPairGenerator.ElGamal", PREFIX + "KeyPairGeneratorSpi");
+
+ AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+ registerOid(provider, OIWObjectIdentifiers.elGamalAlgorithm, "ELGAMAL", keyFact);
+ registerOidAlgorithmParameters(provider, OIWObjectIdentifiers.elGamalAlgorithm, "ELGAMAL");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/GOST.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/GOST.java
new file mode 100644
index 000000000..39e149b7a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/GOST.java
@@ -0,0 +1,49 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.gost.KeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class GOST
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".gost.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyPairGenerator.GOST3410", PREFIX + "KeyPairGeneratorSpi");
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator.GOST-3410", "GOST3410");
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator.GOST-3410-94", "GOST3410");
+
+ provider.addAlgorithm("KeyFactory.GOST3410", PREFIX + "KeyFactorySpi");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.GOST-3410", "GOST3410");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.GOST-3410-94", "GOST3410");
+
+
+ provider.addAlgorithm("AlgorithmParameters.GOST3410", PREFIX + "AlgorithmParametersSpi");
+ provider.addAlgorithm("AlgorithmParameterGenerator.GOST3410", PREFIX + "AlgorithmParameterGeneratorSpi");
+
+ registerOid(provider, CryptoProObjectIdentifiers.gostR3410_94, "GOST3410", new KeyFactorySpi());
+ registerOidAlgorithmParameters(provider, CryptoProObjectIdentifiers.gostR3410_94, "GOST3410");
+
+ provider.addAlgorithm("Signature.GOST3410", PREFIX + "SignatureSpi");
+ provider.addAlgorithm("Alg.Alias.Signature.GOST-3410", "GOST3410");
+ provider.addAlgorithm("Alg.Alias.Signature.GOST-3410-94", "GOST3410");
+ provider.addAlgorithm("Alg.Alias.Signature.GOST3411withGOST3410", "GOST3410");
+ provider.addAlgorithm("Alg.Alias.Signature.GOST3411WITHGOST3410", "GOST3410");
+ provider.addAlgorithm("Alg.Alias.Signature.GOST3411WithGOST3410", "GOST3410");
+ provider.addAlgorithm("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410");
+
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.GOST-3410", "GOST3410");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.GOST-3410", "GOST3410");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/IES.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/IES.java
new file mode 100644
index 000000000..89c438068
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/IES.java
@@ -0,0 +1,23 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class IES
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".ies.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.IES", PREFIX + "AlgorithmParametersSpi");
+ provider.addAlgorithm("Cipher.IES", PREFIX + "CipherSpi$IES");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/RSA.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/RSA.java
new file mode 100644
index 000000000..266c094bb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/RSA.java
@@ -0,0 +1,197 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class RSA
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.asymmetric" + ".rsa.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.OAEP", PREFIX + "AlgorithmParametersSpi$OAEP");
+ provider.addAlgorithm("AlgorithmParameters.PSS", PREFIX + "AlgorithmParametersSpi$PSS");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAANDMGF1", "PSS");
+
+ provider.addAlgorithm("Cipher.RSA", PREFIX + "CipherSpi$NoPadding");
+ provider.addAlgorithm("Cipher.RSA/RAW", PREFIX + "CipherSpi$NoPadding");
+ provider.addAlgorithm("Cipher.RSA/PKCS1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+ provider.addAlgorithm("Cipher.1.2.840.113549.1.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+ provider.addAlgorithm("Cipher.2.5.8.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding");
+ provider.addAlgorithm("Cipher.RSA/1", PREFIX + "CipherSpi$PKCS1v1_5Padding_PrivateOnly");
+ provider.addAlgorithm("Cipher.RSA/2", PREFIX + "CipherSpi$PKCS1v1_5Padding_PublicOnly");
+ provider.addAlgorithm("Cipher.RSA/OAEP", PREFIX + "CipherSpi$OAEPPadding");
+ provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, PREFIX + "CipherSpi$OAEPPadding");
+ provider.addAlgorithm("Cipher.RSA/ISO9796-1", PREFIX + "CipherSpi$ISO9796d1Padding");
+
+ provider.addAlgorithm("Alg.Alias.Cipher.RSA//RAW", "RSA");
+ provider.addAlgorithm("Alg.Alias.Cipher.RSA//NOPADDING", "RSA");
+ provider.addAlgorithm("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
+ provider.addAlgorithm("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
+ provider.addAlgorithm("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
+
+ provider.addAlgorithm("KeyFactory.RSA", PREFIX + "KeyFactorySpi");
+ provider.addAlgorithm("KeyPairGenerator.RSA", PREFIX + "KeyPairGeneratorSpi");
+
+ AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+ registerOid(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA", keyFact);
+ registerOid(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA", keyFact);
+ registerOid(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA", keyFact);
+ registerOid(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "RSA", keyFact);
+
+ registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ registerOidAlgorithmParameters(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA");
+ registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
+ registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
+
+
+ provider.addAlgorithm("Signature.RSASSA-PSS", PREFIX + "PSSSignatureSpi$PSSwithRSA");
+ provider.addAlgorithm("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
+ provider.addAlgorithm("Signature.OID." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA");
+
+ provider.addAlgorithm("Signature.SHA224withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA224withRSA");
+ provider.addAlgorithm("Signature.SHA256withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA256withRSA");
+ provider.addAlgorithm("Signature.SHA384withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA384withRSA");
+ provider.addAlgorithm("Signature.SHA512withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA512withRSA");
+
+ provider.addAlgorithm("Signature.RSA", PREFIX + "DigestSignatureSpi$noneRSA");
+ provider.addAlgorithm("Signature.RAWRSASSA-PSS", PREFIX + "PSSSignatureSpi$nonePSS");
+
+ provider.addAlgorithm("Alg.Alias.Signature.RAWRSA", "RSA");
+ provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSA", "RSA");
+ provider.addAlgorithm("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAANDMGF1", "RAWRSASSA-PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS");
+
+
+ provider.addAlgorithm("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA224WITHRSAANDMGF1", "SHA224withRSA/PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHRSAANDMGF1", "SHA256withRSA/PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA384WITHRSAANDMGF1", "SHA384withRSA/PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHRSAANDMGF1", "SHA512withRSA/PSS");
+
+ if (provider.hasAlgorithm("MessageDigest", "MD2"))
+ {
+ addDigestSignature(provider, "MD2", PREFIX + "DigestSignatureSpi$MD2", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ }
+
+ if (provider.hasAlgorithm("MessageDigest", "MD4"))
+ {
+ addDigestSignature(provider, "MD4", PREFIX + "DigestSignatureSpi$MD4", PKCSObjectIdentifiers.md4WithRSAEncryption);
+ }
+
+ if (provider.hasAlgorithm("MessageDigest", "MD5"))
+ {
+ addDigestSignature(provider, "MD5", PREFIX + "DigestSignatureSpi$MD5", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ provider.addAlgorithm("Signature.MD5withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$MD5WithRSAEncryption");
+ provider.addAlgorithm("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
+ }
+
+ if (provider.hasAlgorithm("MessageDigest", "SHA1"))
+ {
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
+ provider.addAlgorithm("Signature.SHA1withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA1withRSA");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHRSAANDMGF1", "SHA1withRSA/PSS");
+
+ addDigestSignature(provider, "SHA1", PREFIX + "DigestSignatureSpi$SHA1", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2");
+ provider.addAlgorithm("Signature.SHA1withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$SHA1WithRSAEncryption");
+ provider.addAlgorithm("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ provider.addAlgorithm("Alg.Alias.Signature.OID." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ }
+
+ addDigestSignature(provider, "SHA224", PREFIX + "DigestSignatureSpi$SHA224", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ addDigestSignature(provider, "SHA256", PREFIX + "DigestSignatureSpi$SHA256", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+
+ if (provider.hasAlgorithm("MessageDigest", "RIPEMD128"))
+ {
+ addDigestSignature(provider, "RIPEMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ addDigestSignature(provider, "RMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", null);
+ }
+
+ if (provider.hasAlgorithm("MessageDigest", "RIPEMD160"))
+ {
+ addDigestSignature(provider, "RIPEMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ addDigestSignature(provider, "RMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", null);
+ provider.addAlgorithm("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
+ provider.addAlgorithm("Signature.RIPEMD160withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$RIPEMD160WithRSAEncryption");
+ }
+
+ if (provider.hasAlgorithm("MessageDigest", "RIPEMD256"))
+ {
+ addDigestSignature(provider, "RIPEMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ addDigestSignature(provider, "RMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", null);
+ }
+ }
+
+ private void addDigestSignature(
+ ConfigurableProvider provider,
+ String digest,
+ String className,
+ ASN1ObjectIdentifier oid)
+ {
+ String mainName = digest + "WITHRSA";
+ String jdk11Variation1 = digest + "withRSA";
+ String jdk11Variation2 = digest + "WithRSA";
+ String alias = digest + "/" + "RSA";
+ String longName = digest + "WITHRSAENCRYPTION";
+ String longJdk11Variation1 = digest + "withRSAEncryption";
+ String longJdk11Variation2 = digest + "WithRSAEncryption";
+
+ provider.addAlgorithm("Signature." + mainName, className);
+ provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation1, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation2, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + longName, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + longJdk11Variation1, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + longJdk11Variation2, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + alias, mainName);
+
+ if (oid != null)
+ {
+ provider.addAlgorithm("Alg.Alias.Signature." + oid, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName);
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/X509.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/X509.java
new file mode 100644
index 000000000..6b5a9779b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/X509.java
@@ -0,0 +1,31 @@
+package org.spongycastle.jcajce.provider.asymmetric;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+/**
+ * For some reason the class path project thinks that such a KeyFactory will exist.
+ */
+public class X509
+{
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.X.509", "org.spongycastle.jcajce.provider.asymmetric.x509.KeyFactory");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.X509", "X.509");
+
+ //
+ // certificate factories.
+ //
+ provider.addAlgorithm("CertificateFactory.X.509", "org.spongycastle.jcajce.provider.asymmetric.x509.CertificateFactory");
+ provider.addAlgorithm("Alg.Alias.CertificateFactory.X509", "X.509");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 000000000..0b3942877
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,77 @@
+package org.spongycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.crypto.generators.DHParametersGenerator;
+import org.spongycastle.crypto.params.DHParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class AlgorithmParameterGeneratorSpi
+ extends java.security.AlgorithmParameterGeneratorSpi
+{
+ protected SecureRandom random;
+ protected int strength = 1024;
+
+ private int l = 0;
+
+ protected void engineInit(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(genParamSpec instanceof DHGenParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
+ }
+ DHGenParameterSpec spec = (DHGenParameterSpec)genParamSpec;
+
+ this.strength = spec.getPrimeSize();
+ this.l = spec.getExponentSize();
+ this.random = random;
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ DHParametersGenerator pGen = new DHParametersGenerator();
+
+ if (random != null)
+ {
+ pGen.init(strength, 20, random);
+ }
+ else
+ {
+ pGen.init(strength, 20, new SecureRandom());
+ }
+
+ DHParameters p = pGen.generateParameters();
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("DH", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new DHParameterSpec(p.getP(), p.getG(), l));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java
new file mode 100644
index 000000000..ae89fba90
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java
@@ -0,0 +1,142 @@
+package org.spongycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.pkcs.DHParameter;
+
+public class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ DHParameterSpec currentSpec;
+
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+
+
+
+ /**
+ * Return the PKCS#3 ASN.1 structure DHParameter.
+ * <p>
+ * <pre>
+ * DHParameter ::= SEQUENCE {
+ * prime INTEGER, -- p
+ * base INTEGER, -- g
+ * privateValueLength INTEGER OPTIONAL}
+ * </pre>
+ */
+ protected byte[] engineGetEncoded()
+ {
+ DHParameter dhP = new DHParameter(currentSpec.getP(), currentSpec.getG(), currentSpec.getL());
+
+ try
+ {
+ return dhP.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding DHParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == DHParameterSpec.class)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to DH parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof DHParameterSpec))
+ {
+ throw new InvalidParameterSpecException("DHParameterSpec required to initialise a Diffie-Hellman algorithm parameters object");
+ }
+
+ this.currentSpec = (DHParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ DHParameter dhP = DHParameter.getInstance(params);
+
+ if (dhP.getL() != null)
+ {
+ currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG(), dhP.getL().intValue());
+ }
+ else
+ {
+ currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG());
+ }
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid DH Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid DH Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "Diffie-Hellman Parameters";
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java
new file mode 100644
index 000000000..9949a58d7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java
@@ -0,0 +1,213 @@
+package org.spongycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.pkcs.DHParameter;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.DHDomainParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.DHPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+
+public class BCDHPrivateKey
+ implements DHPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 311058815616901812L;
+
+ private BigInteger x;
+
+ private transient DHParameterSpec dhSpec;
+ private transient PrivateKeyInfo info;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCDHPrivateKey()
+ {
+ }
+
+ BCDHPrivateKey(
+ DHPrivateKey key)
+ {
+ this.x = key.getX();
+ this.dhSpec = key.getParams();
+ }
+
+ BCDHPrivateKey(
+ DHPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ }
+
+ public BCDHPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+ ASN1Integer derX = (ASN1Integer)info.parsePrivateKey();
+ ASN1ObjectIdentifier id = info.getPrivateKeyAlgorithm().getAlgorithm();
+
+ this.info = info;
+ this.x = derX.getValue();
+
+ if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ DHParameter params = DHParameter.getInstance(seq);
+
+ if (params.getL() != null)
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+ }
+ else
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ }
+ }
+ else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+ this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm type: " + id);
+ }
+ }
+
+ BCDHPrivateKey(
+ DHPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DH";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ if (info != null)
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+
+ PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(getX()));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return dhSpec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DHPrivateKey))
+ {
+ return false;
+ }
+
+ DHPrivateKey other = (DHPrivateKey)o;
+
+ return this.getX().equals(other.getX())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getL() == other.getParams().getL();
+ }
+
+ public int hashCode()
+ {
+ return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+ this.info = null;
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(dhSpec.getP());
+ out.writeObject(dhSpec.getG());
+ out.writeInt(dhSpec.getL());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
new file mode 100644
index 000000000..26d261abc
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
@@ -0,0 +1,204 @@
+package org.spongycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.pkcs.DHParameter;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.DHDomainParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.DHPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCDHPublicKey
+ implements DHPublicKey
+{
+ static final long serialVersionUID = -216691575254424324L;
+
+ private BigInteger y;
+
+ private transient DHParameterSpec dhSpec;
+ private transient SubjectPublicKeyInfo info;
+
+ BCDHPublicKey(
+ DHPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ }
+
+ BCDHPublicKey(
+ DHPublicKey key)
+ {
+ this.y = key.getY();
+ this.dhSpec = key.getParams();
+ }
+
+ BCDHPublicKey(
+ DHPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ }
+
+ BCDHPublicKey(
+ BigInteger y,
+ DHParameterSpec dhSpec)
+ {
+ this.y = y;
+ this.dhSpec = dhSpec;
+ }
+
+ public BCDHPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ this.info = info;
+
+ ASN1Integer derY;
+ try
+ {
+ derY = (ASN1Integer)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DH public key");
+ }
+
+ this.y = derY.getValue();
+
+ ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithm().getParameters());
+ ASN1ObjectIdentifier id = info.getAlgorithm().getAlgorithm();
+
+ // we need the PKCS check to handle older keys marked with the X9 oid.
+ if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
+ {
+ DHParameter params = DHParameter.getInstance(seq);
+
+ if (params.getL() != null)
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+ }
+ else
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ }
+ }
+ else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+ this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm type: " + id);
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return "DH";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (info != null)
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(y));
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return dhSpec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ private boolean isPKCSParam(ASN1Sequence seq)
+ {
+ if (seq.size() == 2)
+ {
+ return true;
+ }
+
+ if (seq.size() > 3)
+ {
+ return false;
+ }
+
+ ASN1Integer l = ASN1Integer.getInstance(seq.getObjectAt(2));
+ ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(0));
+
+ if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DHPublicKey))
+ {
+ return false;
+ }
+
+ DHPublicKey other = (DHPublicKey)o;
+
+ return this.getY().equals(other.getY())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getL() == other.getParams().getL();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+ this.info = null;
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(dhSpec.getP());
+ out.writeObject(dhSpec.getG());
+ out.writeInt(dhSpec.getL());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/IESCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/IESCipher.java
new file mode 100644
index 000000000..6857f24ac
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/IESCipher.java
@@ -0,0 +1,507 @@
+package org.spongycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+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;
+import javax.crypto.interfaces.DHKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.KeyEncoder;
+import org.spongycastle.crypto.agreement.DHBasicAgreement;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.engines.AESEngine;
+import org.spongycastle.crypto.engines.DESedeEngine;
+import org.spongycastle.crypto.engines.IESEngine;
+import org.spongycastle.crypto.generators.DHKeyPairGenerator;
+import org.spongycastle.crypto.generators.EphemeralKeyPairGenerator;
+import org.spongycastle.crypto.generators.KDF2BytesGenerator;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.DHKeyGenerationParameters;
+import org.spongycastle.crypto.params.DHKeyParameters;
+import org.spongycastle.crypto.params.DHParameters;
+import org.spongycastle.crypto.params.DHPublicKeyParameters;
+import org.spongycastle.crypto.params.IESParameters;
+import org.spongycastle.crypto.params.IESWithCipherParameters;
+import org.spongycastle.crypto.parsers.DHIESPublicKeyParser;
+import org.spongycastle.jcajce.provider.asymmetric.util.DHUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.IESUtil;
+import org.spongycastle.jce.interfaces.IESKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.IESParameterSpec;
+import org.spongycastle.util.BigIntegers;
+import org.spongycastle.util.Strings;
+
+
+public class IESCipher
+ extends CipherSpi
+{
+ private IESEngine engine;
+ private int state = -1;
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ private AlgorithmParameters engineParam = null;
+ private IESParameterSpec engineSpec = null;
+ private AsymmetricKeyParameter key;
+ private SecureRandom random;
+ private boolean dhaesMode = false;
+ private AsymmetricKeyParameter otherKeyParameter = null;
+
+ public IESCipher(IESEngine engine)
+ {
+ this.engine = engine;
+ }
+
+
+ public int engineGetBlockSize()
+ {
+ if (engine.getCipher() != null)
+ {
+ return engine.getCipher().getBlockSize();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+
+ public int engineGetKeySize(Key key)
+ {
+ if (key instanceof DHKey)
+ {
+ return ((DHKey)key).getParams().getP().bitLength();
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a DH key");
+ }
+ }
+
+
+ public byte[] engineGetIV()
+ {
+ return null;
+ }
+
+ public AlgorithmParameters engineGetParameters()
+ {
+ if (engineParam == null && engineSpec != null)
+ {
+ try
+ {
+ engineParam = AlgorithmParameters.getInstance("IES", BouncyCastleProvider.PROVIDER_NAME);
+ engineParam.init(engineSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ return engineParam;
+ }
+
+
+ public void engineSetMode(String mode)
+ throws NoSuchAlgorithmException
+ {
+ String modeName = Strings.toUpperCase(mode);
+
+ if (modeName.equals("NONE"))
+ {
+ dhaesMode = false;
+ }
+ else if (modeName.equals("DHAES"))
+ {
+ dhaesMode = true;
+ }
+ else
+ {
+ throw new IllegalArgumentException("can't support mode " + mode);
+ }
+ }
+
+ public int engineGetOutputSize(int inputLen)
+ {
+ int len1, len2, len3;
+
+ len1 = engine.getMac().getMacSize();
+
+ if (key != null)
+ {
+ len2 = ((DHKey)key).getParams().getP().bitLength() / 8 + 1;
+ }
+ else
+ {
+ throw new IllegalStateException("cipher not initialised");
+ }
+
+ if (engine.getCipher() == null)
+ {
+ len3 = inputLen;
+ }
+ else if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ len3 = engine.getCipher().getOutputSize(inputLen);
+ }
+ else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
+ {
+ len3 = engine.getCipher().getOutputSize(inputLen - len1 - len2);
+ }
+ else
+ {
+ throw new IllegalStateException("cipher not initialised");
+ }
+
+ if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ return buffer.size() + len1 + len2 + len3;
+ }
+ else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
+ {
+ return buffer.size() - len1 - len2 + len3;
+ }
+ else
+ {
+ throw new IllegalStateException("IESCipher not initialised");
+ }
+
+ }
+
+ public void engineSetPadding(String padding)
+ throws NoSuchPaddingException
+ {
+ String paddingName = Strings.toUpperCase(padding);
+
+ // TDOD: make this meaningful...
+ if (paddingName.equals("NOPADDING"))
+ {
+
+ }
+ else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+ {
+
+ }
+ else
+ {
+ throw new NoSuchPaddingException("padding not available with IESCipher");
+ }
+ }
+
+ // Initialisation methods
+
+ public void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(IESParameterSpec.class);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString());
+ }
+ }
+
+ engineParam = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+
+ public void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec engineSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException, InvalidKeyException
+ {
+ // Use default parameters (including cipher key size) if none are specified
+ if (engineSpec == null)
+ {
+ this.engineSpec = IESUtil.guessParameterSpec(engine);
+ }
+ else if (engineSpec instanceof IESParameterSpec)
+ {
+ this.engineSpec = (IESParameterSpec)engineSpec;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("must be passed IES parameters");
+ }
+
+ // Parse the recipient's key
+ if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)
+ {
+ if (key instanceof DHPublicKey)
+ {
+ this.key = DHUtil.generatePublicKeyParameter((PublicKey)key);
+ }
+ else if (key instanceof IESKey)
+ {
+ IESKey ieKey = (IESKey)key;
+
+ this.key = DHUtil.generatePublicKeyParameter(ieKey.getPublic());
+ this.otherKeyParameter = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate());
+ }
+ else
+ {
+ throw new InvalidKeyException("must be passed recipient's public DH key for encryption");
+ }
+ }
+ else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE)
+ {
+ if (key instanceof DHPrivateKey)
+ {
+ this.key = DHUtil.generatePrivateKeyParameter((PrivateKey)key);
+ }
+ else if (key instanceof IESKey)
+ {
+ IESKey ieKey = (IESKey)key;
+
+ this.otherKeyParameter = DHUtil.generatePublicKeyParameter(ieKey.getPublic());
+ this.key = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate());
+ }
+ else
+ {
+ throw new InvalidKeyException("must be passed recipient's private DH key for decryption");
+ }
+ }
+ else
+ {
+ throw new InvalidKeyException("must be passed EC key");
+ }
+
+ this.random = random;
+ this.state = opmode;
+ buffer.reset();
+
+ }
+
+
+ public void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new IllegalArgumentException("can't handle supplied parameter spec");
+ }
+
+ }
+
+
+ // Update methods - buffer the input
+
+ public byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ return null;
+ }
+
+
+ public int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ return 0;
+ }
+
+
+ // Finalisation methods
+
+ public byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (inputLen != 0)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ }
+
+ byte[] in = buffer.toByteArray();
+ buffer.reset();
+
+ // Convert parameters for use in IESEngine
+ IESParameters params = new IESWithCipherParameters(engineSpec.getDerivationV(),
+ engineSpec.getEncodingV(),
+ engineSpec.getMacKeySize(),
+ engineSpec.getCipherKeySize());
+
+ DHParameters dhParams = ((DHKeyParameters)key).getParameters();
+
+ byte[] V;
+ if (otherKeyParameter != null)
+ {
+ try
+ {
+ if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ engine.init(true, otherKeyParameter, key, params);
+ }
+ else
+ {
+ engine.init(false, key, otherKeyParameter, params);
+ }
+ return engine.processBlock(in, 0, in.length);
+ }
+ catch (Exception e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ // Generate the ephemeral key pair
+ DHKeyPairGenerator gen = new DHKeyPairGenerator();
+ gen.init(new DHKeyGenerationParameters(random, dhParams));
+
+ EphemeralKeyPairGenerator kGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder()
+ {
+ public byte[] getEncoded(AsymmetricKeyParameter keyParameter)
+ {
+ byte[] Vloc = new byte[(((DHKeyParameters)keyParameter).getParameters().getP().bitLength() + 7) / 8];
+ byte[] Vtmp = BigIntegers.asUnsignedByteArray(((DHPublicKeyParameters)keyParameter).getY());
+
+ if (Vtmp.length > Vloc.length)
+ {
+ throw new IllegalArgumentException("Senders's public key longer than expected.");
+ }
+ else
+ {
+ System.arraycopy(Vtmp, 0, Vloc, Vloc.length - Vtmp.length, Vtmp.length);
+ }
+
+ return Vloc;
+ }
+ });
+
+ // Encrypt the buffer
+ try
+ {
+ engine.init(key, params, kGen);
+
+ return engine.processBlock(in, 0, in.length);
+ }
+ catch (Exception e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+ else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
+ {
+ // Decrypt the buffer
+ try
+ {
+ engine.init(key, params, new DHIESPublicKeyParser(((DHKeyParameters)key).getParameters()));
+
+ return engine.processBlock(in, 0, in.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+ else
+ {
+ throw new IllegalStateException("IESCipher not initialised");
+ }
+
+ }
+
+
+ public int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLength,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
+ {
+
+ byte[] buf = engineDoFinal(input, inputOffset, inputLength);
+ System.arraycopy(buf, 0, output, outputOffset, buf.length);
+ return buf.length;
+
+ }
+
+
+ /**
+ * Classes that inherit from us
+ */
+
+ static public class IES
+ extends IESCipher
+ {
+ public IES()
+ {
+ super(new IESEngine(new DHBasicAgreement(),
+ new KDF2BytesGenerator(new SHA1Digest()),
+ new HMac(new SHA1Digest())));
+ }
+ }
+
+ static public class IESwithDESede
+ extends IESCipher
+ {
+ public IESwithDESede()
+ {
+ super(new IESEngine(new DHBasicAgreement(),
+ new KDF2BytesGenerator(new SHA1Digest()),
+ new HMac(new SHA1Digest()),
+ new PaddedBufferedBlockCipher(new DESedeEngine())));
+ }
+ }
+
+ static public class IESwithAES
+ extends IESCipher
+ {
+ public IESwithAES()
+ {
+ super(new IESEngine(new DHBasicAgreement(),
+ new KDF2BytesGenerator(new SHA1Digest()),
+ new HMac(new SHA1Digest()),
+ new PaddedBufferedBlockCipher(new AESEngine())));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
new file mode 100644
index 000000000..631272363
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
@@ -0,0 +1,227 @@
+package org.spongycastle.jcajce.provider.asymmetric.dh;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+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;
+
+import org.spongycastle.crypto.params.DESParameters;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.Strings;
+
+/**
+ * Diffie-Hellman key agreement. There's actually a better way of doing this
+ * if you are using long term public keys, see the light-weight version for
+ * details.
+ */
+public class KeyAgreementSpi
+ extends javax.crypto.KeyAgreementSpi
+{
+ private BigInteger x;
+ private BigInteger p;
+ private BigInteger g;
+ private BigInteger result;
+
+ private static final Hashtable algorithms = new Hashtable();
+
+ static
+ {
+ Integer i64 = Integers.valueOf(64);
+ Integer i192 = Integers.valueOf(192);
+ Integer i128 = Integers.valueOf(128);
+ Integer i256 = Integers.valueOf(256);
+
+ algorithms.put("DES", i64);
+ algorithms.put("DESEDE", i192);
+ algorithms.put("BLOWFISH", i128);
+ algorithms.put("AES", i256);
+ }
+
+ private byte[] bigIntToBytes(
+ BigInteger r)
+ {
+ //
+ // RFC 2631 (2.1.2) specifies that the secret should be padded with leading zeros if necessary
+ // must be the same length as p
+ //
+ int expectedLength = (p.bitLength() + 7) / 8;
+
+ byte[] tmp = r.toByteArray();
+
+ if (tmp.length == expectedLength)
+ {
+ return tmp;
+ }
+
+ if (tmp[0] == 0 && tmp.length == expectedLength + 1)
+ {
+ byte[] rv = new byte[tmp.length - 1];
+
+ System.arraycopy(tmp, 1, rv, 0, rv.length);
+ return rv;
+ }
+
+ // tmp must be shorter than expectedLength
+ // pad to the left with zeros.
+ byte[] rv = new byte[expectedLength];
+
+ System.arraycopy(tmp, 0, rv, rv.length - tmp.length, tmp.length);
+
+ return rv;
+ }
+
+ protected Key engineDoPhase(
+ Key key,
+ boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ if (x == null)
+ {
+ throw new IllegalStateException("Diffie-Hellman not initialised.");
+ }
+
+ if (!(key instanceof DHPublicKey))
+ {
+ throw new InvalidKeyException("DHKeyAgreement doPhase requires DHPublicKey");
+ }
+ DHPublicKey pubKey = (DHPublicKey)key;
+
+ if (!pubKey.getParams().getG().equals(g) || !pubKey.getParams().getP().equals(p))
+ {
+ throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
+ }
+
+ if (lastPhase)
+ {
+ result = ((DHPublicKey)key).getY().modPow(x, p);
+ return null;
+ }
+ else
+ {
+ result = ((DHPublicKey)key).getY().modPow(x, p);
+ }
+
+ return new BCDHPublicKey(result, pubKey.getParams());
+ }
+
+ protected byte[] engineGenerateSecret()
+ throws IllegalStateException
+ {
+ if (x == null)
+ {
+ throw new IllegalStateException("Diffie-Hellman not initialised.");
+ }
+
+ return bigIntToBytes(result);
+ }
+
+ protected int engineGenerateSecret(
+ byte[] sharedSecret,
+ int offset)
+ throws IllegalStateException, ShortBufferException
+ {
+ if (x == null)
+ {
+ throw new IllegalStateException("Diffie-Hellman not initialised.");
+ }
+
+ byte[] secret = bigIntToBytes(result);
+
+ if (sharedSecret.length - offset < secret.length)
+ {
+ throw new ShortBufferException("DHKeyAgreement - buffer too short");
+ }
+
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+
+ return secret.length;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ String algorithm)
+ {
+ if (x == null)
+ {
+ throw new IllegalStateException("Diffie-Hellman not initialised.");
+ }
+
+ String algKey = Strings.toUpperCase(algorithm);
+ byte[] res = bigIntToBytes(result);
+
+ if (algorithms.containsKey(algKey))
+ {
+ Integer length = (Integer)algorithms.get(algKey);
+
+ byte[] key = new byte[length.intValue() / 8];
+ System.arraycopy(res, 0, key, 0, key.length);
+
+ if (algKey.startsWith("DES"))
+ {
+ DESParameters.setOddParity(key);
+ }
+
+ return new SecretKeySpec(key, algorithm);
+ }
+
+ return new SecretKeySpec(res, algorithm);
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ if (!(key instanceof DHPrivateKey))
+ {
+ throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey for initialisation");
+ }
+ DHPrivateKey privKey = (DHPrivateKey)key;
+
+ if (params != null)
+ {
+ if (!(params instanceof DHParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec");
+ }
+ DHParameterSpec p = (DHParameterSpec)params;
+
+ this.p = p.getP();
+ this.g = p.getG();
+ }
+ else
+ {
+ this.p = privKey.getParams().getP();
+ this.g = privKey.getParams().getG();
+ }
+
+ this.x = this.result = privKey.getX();
+ }
+
+ protected void engineInit(
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (!(key instanceof DHPrivateKey))
+ {
+ throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey");
+ }
+
+ DHPrivateKey privKey = (DHPrivateKey)key;
+
+ this.p = privKey.getParams().getP();
+ this.g = privKey.getParams().getG();
+ this.x = this.result = privKey.getX();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
new file mode 100644
index 000000000..92ccdd3e7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
@@ -0,0 +1,128 @@
+package org.spongycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(DHPrivateKeySpec.class) && key instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)key;
+
+ return new DHPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getG());
+ }
+ else if (spec.isAssignableFrom(DHPublicKeySpec.class) && key instanceof DHPublicKey)
+ {
+ DHPublicKey k = (DHPublicKey)key;
+
+ return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPublicKey)
+ {
+ return new BCDHPublicKey((DHPublicKey)key);
+ }
+ else if (key instanceof DHPrivateKey)
+ {
+ return new BCDHPrivateKey((DHPrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DHPrivateKeySpec)
+ {
+ return new BCDHPrivateKey((DHPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DHPublicKeySpec)
+ {
+ return new BCDHPublicKey((DHPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ return new BCDHPrivateKey(keyInfo);
+ }
+ else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ return new BCDHPrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ return new BCDHPublicKey(keyInfo);
+ }
+ else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ return new BCDHPublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..67b0d5dc9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
@@ -0,0 +1,119 @@
+package org.spongycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.DHBasicKeyPairGenerator;
+import org.spongycastle.crypto.generators.DHParametersGenerator;
+import org.spongycastle.crypto.params.DHKeyGenerationParameters;
+import org.spongycastle.crypto.params.DHParameters;
+import org.spongycastle.crypto.params.DHPrivateKeyParameters;
+import org.spongycastle.crypto.params.DHPublicKeyParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Integers;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ private static Hashtable params = new Hashtable();
+ private static Object lock = new Object();
+
+ DHKeyGenerationParameters param;
+ DHBasicKeyPairGenerator engine = new DHBasicKeyPairGenerator();
+ int strength = 1024;
+ int certainty = 20;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("DH");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof DHParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec");
+ }
+ DHParameterSpec dhParams = (DHParameterSpec)params;
+
+ param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL()));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ Integer paramStrength = Integers.valueOf(strength);
+
+ if (params.containsKey(paramStrength))
+ {
+ param = (DHKeyGenerationParameters)params.get(paramStrength);
+ }
+ else
+ {
+ DHParameterSpec dhParams = BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(strength);
+
+ if (dhParams != null)
+ {
+ param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL()));
+ }
+ else
+ {
+ synchronized (lock)
+ {
+ // we do the check again in case we were blocked by a generator for
+ // our key size.
+ if (params.containsKey(paramStrength))
+ {
+ param = (DHKeyGenerationParameters)params.get(paramStrength);
+ }
+ else
+ {
+
+ DHParametersGenerator pGen = new DHParametersGenerator();
+
+ pGen.init(strength, certainty, random);
+
+ param = new DHKeyGenerationParameters(random, pGen.generateParameters());
+
+ params.put(paramStrength, param);
+ }
+ }
+ }
+ }
+
+ engine.init(param);
+
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ DHPublicKeyParameters pub = (DHPublicKeyParameters)pair.getPublic();
+ DHPrivateKeyParameters priv = (DHPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCDHPublicKey(pub),
+ new BCDHPrivateKey(priv));
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 000000000..9bbdca3d3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,103 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.generators.DSAParametersGenerator;
+import org.spongycastle.crypto.params.DSAParameterGenerationParameters;
+import org.spongycastle.crypto.params.DSAParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class AlgorithmParameterGeneratorSpi
+ extends java.security.AlgorithmParameterGeneratorSpi
+{
+ protected SecureRandom random;
+ protected int strength = 1024;
+ protected DSAParameterGenerationParameters params;
+
+ protected void engineInit(
+ int strength,
+ SecureRandom random)
+ {
+ if (strength < 512 || strength > 3072)
+ {
+ throw new InvalidParameterException("strength must be from 512 - 3072");
+ }
+
+ if (strength <= 1024 && strength % 64 != 0)
+ {
+ throw new InvalidParameterException("strength must be a multiple of 64 below 1024 bits.");
+ }
+
+ if (strength > 1024 && strength % 1024 != 0)
+ {
+ throw new InvalidParameterException("strength must be a multiple of 1024 above 1024 bits.");
+ }
+
+ this.strength = strength;
+ this.random = random;
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DSA parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ DSAParametersGenerator pGen;
+
+ if (strength <= 1024)
+ {
+ pGen = new DSAParametersGenerator();
+ }
+ else
+ {
+ pGen = new DSAParametersGenerator(new SHA256Digest());
+ }
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if (strength == 1024)
+ {
+ params = new DSAParameterGenerationParameters(1024, 160, 80, random);
+ pGen.init(params);
+ }
+ else if (strength > 1024)
+ {
+ params = new DSAParameterGenerationParameters(strength, 256, 80, random);
+ pGen.init(params);
+ }
+ else
+ {
+ pGen.init(strength, 20, random);
+ }
+
+ DSAParameters p = pGen.generateParameters();
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new DSAParameterSpec(p.getP(), p.getQ(), p.getG()));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java
new file mode 100644
index 000000000..2ace504db
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java
@@ -0,0 +1,132 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.x509.DSAParameter;
+
+public class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ DSAParameterSpec currentSpec;
+
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ /**
+ * Return the X.509 ASN.1 structure DSAParameter.
+ * <p/>
+ * <pre>
+ * DSAParameter ::= SEQUENCE {
+ * prime INTEGER, -- p
+ * subprime INTEGER, -- q
+ * base INTEGER, -- g}
+ * </pre>
+ */
+ protected byte[] engineGetEncoded()
+ {
+ DSAParameter dsaP = new DSAParameter(currentSpec.getP(), currentSpec.getQ(), currentSpec.getG());
+
+ try
+ {
+ return dsaP.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding DSAParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == DSAParameterSpec.class)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to DSA parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof DSAParameterSpec))
+ {
+ throw new InvalidParameterSpecException("DSAParameterSpec required to initialise a DSA algorithm parameters object");
+ }
+
+ this.currentSpec = (DSAParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ DSAParameter dsaP = DSAParameter.getInstance(ASN1Primitive.fromByteArray(params));
+
+ currentSpec = new DSAParameterSpec(dsaP.getP(), dsaP.getQ(), dsaP.getG());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid DSA Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid DSA Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "DSA Parameters";
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java
new file mode 100644
index 000000000..bcd3dfe86
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java
@@ -0,0 +1,167 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DSAParameter;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.DSAPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class BCDSAPrivateKey
+ implements DSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ private static final long serialVersionUID = -4677259546958385734L;
+
+ private BigInteger x;
+ private transient DSAParams dsaSpec;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCDSAPrivateKey()
+ {
+ }
+
+ BCDSAPrivateKey(
+ DSAPrivateKey key)
+ {
+ this.x = key.getX();
+ this.dsaSpec = key.getParams();
+ }
+
+ BCDSAPrivateKey(
+ DSAPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ public BCDSAPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ DSAParameter params = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+ ASN1Integer derX = (ASN1Integer)info.parsePrivateKey();
+
+ this.x = derX.getValue();
+ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+ }
+
+ BCDSAPrivateKey(
+ DSAPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DSA";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).toASN1Primitive()), new ASN1Integer(getX()));
+ }
+
+ public DSAParams getParams()
+ {
+ return dsaSpec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAPrivateKey))
+ {
+ return false;
+ }
+
+ DSAPrivateKey other = (DSAPrivateKey)o;
+
+ return this.getX().equals(other.getX())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+
+ public int hashCode()
+ {
+ return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
new file mode 100644
index 000000000..f4ccaeae0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
@@ -0,0 +1,171 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DSAParameter;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.DSAPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCDSAPublicKey
+ implements DSAPublicKey
+{
+ private static final long serialVersionUID = 1752452449903495175L;
+
+ private BigInteger y;
+ private transient DSAParams dsaSpec;
+
+ BCDSAPublicKey(
+ DSAPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ BCDSAPublicKey(
+ DSAPublicKey key)
+ {
+ this.y = key.getY();
+ this.dsaSpec = key.getParams();
+ }
+
+ BCDSAPublicKey(
+ DSAPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+
+ BCDSAPublicKey(
+ BigInteger y,
+ DSAParameterSpec dsaSpec)
+ {
+ this.y = y;
+ this.dsaSpec = dsaSpec;
+ }
+
+ public BCDSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+
+ ASN1Integer derY;
+
+ try
+ {
+ derY = (ASN1Integer)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DSA public key");
+ }
+
+ this.y = derY.getValue();
+
+ if (isNotNull(info.getAlgorithm().getParameters()))
+ {
+ DSAParameter params = DSAParameter.getInstance(info.getAlgorithm().getParameters());
+
+ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+ }
+ }
+
+ private boolean isNotNull(ASN1Encodable parameters)
+ {
+ return parameters != null && !DERNull.INSTANCE.equals(parameters.toASN1Primitive());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (dsaSpec == null)
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(y));
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).toASN1Primitive()), new ASN1Integer(y));
+ }
+
+ public DSAParams getParams()
+ {
+ return dsaSpec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("DSA Public Key").append(nl);
+ buf.append(" y: ").append(this.getY().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ public int hashCode()
+ {
+ return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAPublicKey))
+ {
+ return false;
+ }
+
+ DSAPublicKey other = (DSAPublicKey)o;
+
+ return this.getY().equals(other.getY())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
new file mode 100644
index 000000000..c2b9e5d32
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
@@ -0,0 +1,313 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.DSAKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.NullDigest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.HMacDSAKCalculator;
+
+public class DSASigner
+ extends SignatureSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+ private SecureRandom random;
+
+ protected DSASigner(
+ Digest digest,
+ DSA signer)
+ {
+ this.digest = digest;
+ this.signer = signer;
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof DSAKey)
+ {
+ param = DSAUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof DSAKey)
+ {
+ param = DSAUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ param = DSAUtil.generatePrivateKeyParameter(privateKey);
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ digest.reset();
+ signer.init(true, param);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+
+ return derEncode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ sig = derDecode(sigBytes);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ private byte[] derEncode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ ASN1Integer[] rs = new ASN1Integer[]{ new ASN1Integer(r), new ASN1Integer(s) };
+ return new DERSequence(rs).getEncoded(ASN1Encoding.DER);
+ }
+
+ private BigInteger[] derDecode(
+ byte[] encoding)
+ throws IOException
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ return new BigInteger[]{
+ ((ASN1Integer)s.getObjectAt(0)).getValue(),
+ ((ASN1Integer)s.getObjectAt(1)).getValue()
+ };
+ }
+
+ static public class stdDSA
+ extends DSASigner
+ {
+ public stdDSA()
+ {
+ super(new SHA1Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSA
+ extends DSASigner
+ {
+ public detDSA()
+ {
+ super(new SHA1Digest(), new org.spongycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA1Digest())));
+ }
+ }
+
+ static public class dsa224
+ extends DSASigner
+ {
+ public dsa224()
+ {
+ super(new SHA224Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSA224
+ extends DSASigner
+ {
+ public detDSA224()
+ {
+ super(new SHA224Digest(), new org.spongycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA224Digest())));
+ }
+ }
+
+ static public class dsa256
+ extends DSASigner
+ {
+ public dsa256()
+ {
+ super(new SHA256Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSA256
+ extends DSASigner
+ {
+ public detDSA256()
+ {
+ super(new SHA256Digest(), new org.spongycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA256Digest())));
+ }
+ }
+
+ static public class dsa384
+ extends DSASigner
+ {
+ public dsa384()
+ {
+ super(new SHA384Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSA384
+ extends DSASigner
+ {
+ public detDSA384()
+ {
+ super(new SHA384Digest(), new org.spongycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA384Digest())));
+ }
+ }
+
+ static public class dsa512
+ extends DSASigner
+ {
+ public dsa512()
+ {
+ super(new SHA512Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class detDSA512
+ extends DSASigner
+ {
+ public detDSA512()
+ {
+ super(new SHA512Digest(), new org.spongycastle.crypto.signers.DSASigner(new HMacDSAKCalculator(new SHA512Digest())));
+ }
+ }
+
+ static public class noneDSA
+ extends DSASigner
+ {
+ public noneDSA()
+ {
+ super(new NullDigest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
new file mode 100644
index 000000000..ae627195b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
@@ -0,0 +1,72 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.DSAParameters;
+import org.spongycastle.crypto.params.DSAPrivateKeyParameters;
+import org.spongycastle.crypto.params.DSAPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DSA objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class DSAUtil
+{
+ public static final ASN1ObjectIdentifier[] dsaOids =
+ {
+ X9ObjectIdentifiers.id_dsa,
+ OIWObjectIdentifiers.dsaWithSHA1
+ };
+
+ public static boolean isDsaOid(
+ ASN1ObjectIdentifier algOid)
+ {
+ for (int i = 0; i != dsaOids.length; i++)
+ {
+ if (algOid.equals(dsaOids[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DSAPublicKey)
+ {
+ DSAPublicKey k = (DSAPublicKey)key;
+
+ return new DSAPublicKeyParameters(k.getY(),
+ new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()));
+ }
+
+ throw new InvalidKeyException("can't identify DSA public key: " + key.getClass().getName());
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DSAPrivateKey)
+ {
+ DSAPrivateKey k = (DSAPrivateKey)key;
+
+ return new DSAPrivateKeyParameters(k.getX(),
+ new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()));
+ }
+
+ throw new InvalidKeyException("can't identify DSA private key.");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
new file mode 100644
index 000000000..2b5c693ed
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
@@ -0,0 +1,117 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(DSAPublicKeySpec.class) && key instanceof DSAPublicKey)
+ {
+ DSAPublicKey k = (DSAPublicKey)key;
+
+ return new DSAPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+ }
+ else if (spec.isAssignableFrom(DSAPrivateKeySpec.class) && key instanceof java.security.interfaces.DSAPrivateKey)
+ {
+ java.security.interfaces.DSAPrivateKey k = (java.security.interfaces.DSAPrivateKey)key;
+
+ return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DSAPublicKey)
+ {
+ return new BCDSAPublicKey((DSAPublicKey)key);
+ }
+ else if (key instanceof DSAPrivateKey)
+ {
+ return new BCDSAPrivateKey((DSAPrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (DSAUtil.isDsaOid(algOid))
+ {
+ return new BCDSAPrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (DSAUtil.isDsaOid(algOid))
+ {
+ return new BCDSAPublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DSAPrivateKeySpec)
+ {
+ return new BCDSAPrivateKey((DSAPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DSAPublicKeySpec)
+ {
+ return new BCDSAPublicKey((DSAPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..ecad1e87e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,82 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.DSAKeyPairGenerator;
+import org.spongycastle.crypto.generators.DSAParametersGenerator;
+import org.spongycastle.crypto.params.DSAKeyGenerationParameters;
+import org.spongycastle.crypto.params.DSAParameters;
+import org.spongycastle.crypto.params.DSAPrivateKeyParameters;
+import org.spongycastle.crypto.params.DSAPublicKeyParameters;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ DSAKeyGenerationParameters param;
+ DSAKeyPairGenerator engine = new DSAKeyPairGenerator();
+ int strength = 1024;
+ int certainty = 20;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("DSA");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ if (strength < 512 || strength > 1024 || strength % 64 != 0)
+ {
+ throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
+ }
+
+ this.strength = strength;
+ this.random = random;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof DSAParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a DSAParameterSpec");
+ }
+ DSAParameterSpec dsaParams = (DSAParameterSpec)params;
+
+ param = new DSAKeyGenerationParameters(random, new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ DSAParametersGenerator pGen = new DSAParametersGenerator();
+
+ pGen.init(strength, certainty, random);
+ param = new DSAKeyGenerationParameters(random, pGen.generateParameters());
+ engine.init(param);
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ DSAPublicKeyParameters pub = (DSAPublicKeyParameters)pair.getPublic();
+ DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCDSAPublicKey(pub),
+ new BCDSAPrivateKey(priv));
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java
new file mode 100644
index 000000000..ac595e20b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java
@@ -0,0 +1,468 @@
+package org.spongycastle.jcajce.provider.asymmetric.dstu;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.ua.DSTU4145NamedCurves;
+import org.spongycastle.asn1.ua.UAObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class BCDSTU4145PrivateKey
+ implements ECPrivateKey, org.spongycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ static final long serialVersionUID = 7245981689601667138L;
+
+ private String algorithm = "DSTU4145";
+ private boolean withCompression;
+
+ private transient BigInteger d;
+ private transient ECParameterSpec ecSpec;
+ private transient DERBitString publicKey;
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCDSTU4145PrivateKey()
+ {
+ }
+
+ public BCDSTU4145PrivateKey(
+ ECPrivateKey key)
+ {
+ this.d = key.getS();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ }
+
+ public BCDSTU4145PrivateKey(
+ org.spongycastle.jce.spec.ECPrivateKeySpec spec)
+ {
+ this.d = spec.getD();
+
+ if (spec.getParams() != null) // can be null if implicitlyCA
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve;
+
+ ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ this.ecSpec = null;
+ }
+ }
+
+
+ public BCDSTU4145PrivateKey(
+ ECPrivateKeySpec spec)
+ {
+ this.d = spec.getS();
+ this.ecSpec = spec.getParams();
+ }
+
+ public BCDSTU4145PrivateKey(
+ BCDSTU4145PrivateKey key)
+ {
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.attrCarrier = key.attrCarrier;
+ this.publicKey = key.publicKey;
+ }
+
+ public BCDSTU4145PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCDSTU4145PublicKey pubKey,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCDSTU4145PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCDSTU4145PublicKey pubKey,
+ org.spongycastle.jce.spec.ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(),
+ spec.getH().intValue());
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCDSTU4145PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ }
+
+ BCDSTU4145PrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ populateFromPrivKeyInfo(info);
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ throws IOException
+ {
+ X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ if (ecP == null) // DSTU Curve
+ {
+ ECDomainParameters gParam = DSTU4145NamedCurves.getByOID(oid);
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ oid.getId(),
+ ellipticCurve,
+ new ECPoint(
+ gParam.getG().getAffineXCoord().toBigInteger(),
+ gParam.getG().getAffineYCoord().toBigInteger()),
+ gParam.getN(),
+ gParam.getH());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECUtil.getCurveName(oid),
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH());
+ }
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ ASN1Encodable privKey = info.parsePrivateKey();
+ if (privKey instanceof DERInteger)
+ {
+ DERInteger derD = DERInteger.getInstance(privKey);
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ org.spongycastle.asn1.sec.ECPrivateKey ec = org.spongycastle.asn1.sec.ECPrivateKey.getInstance(privKey);
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ X962Parameters params;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null) // guess it's the OID
+ {
+ curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ org.spongycastle.asn1.sec.ECPrivateKey keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new org.spongycastle.asn1.sec.ECPrivateKey(this.getS(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new org.spongycastle.asn1.sec.ECPrivateKey(this.getS(), params);
+ }
+
+ try
+ {
+ if (algorithm.equals("DSTU4145"))
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(UAObjectIdentifiers.dstu4145be, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+ }
+ else
+ {
+
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+ }
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.spongycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null)
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public BigInteger getS()
+ {
+ return d;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCDSTU4145PrivateKey))
+ {
+ return false;
+ }
+
+ BCDSTU4145PrivateKey other = (BCDSTU4145PrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Private Key").append(nl);
+ buf.append(" S: ").append(this.d.toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ private DERBitString getPublicKeyDetails(BCDSTU4145PublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java
new file mode 100644
index 000000000..e2c1aed8d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java
@@ -0,0 +1,436 @@
+package org.spongycastle.jcajce.provider.asymmetric.dstu;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ua.DSTU4145BinaryField;
+import org.spongycastle.asn1.ua.DSTU4145ECBinary;
+import org.spongycastle.asn1.ua.DSTU4145NamedCurves;
+import org.spongycastle.asn1.ua.DSTU4145Params;
+import org.spongycastle.asn1.ua.DSTU4145PointEncoder;
+import org.spongycastle.asn1.ua.UAObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class BCDSTU4145PublicKey
+ implements ECPublicKey, org.spongycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+ static final long serialVersionUID = 7026240464295649314L;
+
+ private String algorithm = "DSTU4145";
+ private boolean withCompression;
+
+ private transient org.spongycastle.math.ec.ECPoint q;
+ private transient ECParameterSpec ecSpec;
+ private transient DSTU4145Params dstuParams;
+
+ public BCDSTU4145PublicKey(
+ BCDSTU4145PublicKey key)
+ {
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.dstuParams = key.dstuParams;
+ }
+
+ public BCDSTU4145PublicKey(
+ ECPublicKeySpec spec)
+ {
+ this.ecSpec = spec.getParams();
+ this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ }
+
+ public BCDSTU4145PublicKey(
+ org.spongycastle.jce.spec.ECPublicKeySpec spec)
+ {
+ this.q = spec.getQ();
+
+ if (spec.getParams() != null) // can be null if implictlyCa
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.spongycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
+ }
+ this.ecSpec = null;
+ }
+ }
+
+ public BCDSTU4145PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+ }
+
+ public BCDSTU4145PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ org.spongycastle.jce.spec.ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+ }
+ }
+
+ /*
+ * called for implicitCA
+ */
+ public BCDSTU4145PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ }
+
+ private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+ {
+ return new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+
+ public BCDSTU4145PublicKey(
+ ECPublicKey key)
+ {
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+ }
+
+ BCDSTU4145PublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ populateFromPubKeyInfo(info);
+ }
+
+ private void reverseBytes(byte[] bytes)
+ {
+ byte tmp;
+
+ for (int i = 0; i < bytes.length / 2; i++)
+ {
+ tmp = bytes[i];
+ bytes[i] = bytes[bytes.length - 1 - i];
+ bytes[bytes.length - 1 - i] = tmp;
+ }
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ DERBitString bits = info.getPublicKeyData();
+ ASN1OctetString key;
+ this.algorithm = "DSTU4145";
+
+ try
+ {
+ key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes());
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+
+ byte[] keyEnc = key.getOctets();
+
+ if (info.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le))
+ {
+ reverseBytes(keyEnc);
+ }
+
+ dstuParams = DSTU4145Params.getInstance((ASN1Sequence)info.getAlgorithm().getParameters());
+
+ //ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+ org.spongycastle.jce.spec.ECParameterSpec spec = null;
+ if (dstuParams.isNamedCurve())
+ {
+ ASN1ObjectIdentifier curveOid = dstuParams.getNamedCurve();
+ ECDomainParameters ecP = DSTU4145NamedCurves.getByOID(curveOid);
+
+ spec = new ECNamedCurveParameterSpec(curveOid.getId(), ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed());
+ }
+ else
+ {
+ DSTU4145ECBinary binary = dstuParams.getECBinary();
+ byte[] b_bytes = binary.getB();
+ if (info.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le))
+ {
+ reverseBytes(b_bytes);
+ }
+ DSTU4145BinaryField field = binary.getField();
+ ECCurve curve = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), new BigInteger(1, b_bytes));
+ byte[] g_bytes = binary.getG();
+ if (info.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le))
+ {
+ reverseBytes(g_bytes);
+ }
+ spec = new org.spongycastle.jce.spec.ECParameterSpec(curve, DSTU4145PointEncoder.decodePoint(curve, g_bytes), binary.getN());
+ }
+
+ ECCurve curve = spec.getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
+
+ //this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
+ this.q = DSTU4145PointEncoder.decodePoint(curve, keyEnc);
+
+ if (dstuParams.isNamedCurve())
+ {
+ ecSpec = new ECNamedCurveSpec(
+ dstuParams.getNamedCurve().getId(),
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(), spec.getH());
+ }
+ else
+ {
+ ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(), spec.getH().intValue());
+ }
+ }
+
+ public byte[] getSbox()
+ {
+ if (null != dstuParams)
+ {
+ return dstuParams.getDKE();
+ }
+ else
+ {
+ return DSTU4145Params.getDefaultDKE();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ ASN1Encodable params;
+ SubjectPublicKeyInfo info;
+
+ if (dstuParams != null)
+ {
+ params = dstuParams;
+ }
+ else
+ {
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ params = new DSTU4145Params(new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()));
+ }
+ else
+ { // strictly speaking this may not be applicable...
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+ }
+
+ byte[] encKey = DSTU4145PointEncoder.encodePoint(this.q);
+
+ try
+ {
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(UAObjectIdentifiers.dstu4145be, params), new DEROctetString(encKey));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.spongycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null) // implictlyCA
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ public ECPoint getW()
+ {
+ return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
+ }
+
+ public org.spongycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.spongycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.spongycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord());
+ }
+ else
+ {
+ return new org.spongycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord());
+ }
+ }
+
+ return q;
+ }
+
+ public org.spongycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCDSTU4145PublicKey))
+ {
+ return false;
+ }
+
+ BCDSTU4145PublicKey other = (BCDSTU4145PublicKey)o;
+
+ return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java
new file mode 100644
index 000000000..995db98c8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java
@@ -0,0 +1,166 @@
+package org.spongycastle.jcajce.provider.asymmetric.dstu;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.ua.UAObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+ }
+ }
+ else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false));
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec);
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false));
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec);
+ }
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPrivateKeySpec)
+ {
+ return new BCDSTU4145PrivateKey((ECPrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
+ {
+ return new BCDSTU4145PrivateKey((java.security.spec.ECPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCDSTU4145PublicKey((ECPublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+ {
+ return new BCDSTU4145PublicKey((java.security.spec.ECPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(UAObjectIdentifiers.dstu4145le) || algOid.equals(UAObjectIdentifiers.dstu4145be))
+ {
+ return new BCDSTU4145PrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(UAObjectIdentifiers.dstu4145le) || algOid.equals(UAObjectIdentifiers.dstu4145be))
+ {
+ return new BCDSTU4145PublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..4c9cbaa6c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java
@@ -0,0 +1,188 @@
+package org.spongycastle.jcajce.provider.asymmetric.dstu;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ua.DSTU4145NamedCurves;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.DSTU4145KeyPairGenerator;
+import org.spongycastle.crypto.generators.ECKeyPairGenerator;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECKeyGenerationParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ Object ecParams = null;
+ ECKeyPairGenerator engine = new DSTU4145KeyPairGenerator();
+
+ String algorithm = "DSTU4145";
+ ECKeyGenerationParameters param;
+ //int strength = 239;
+ SecureRandom random = null;
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("DSTU4145");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.random = random;
+
+ if (ecParams != null)
+ {
+ try
+ {
+ initialize((ECGenParameterSpec)ecParams, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException("key size not configurable.");
+ }
+ }
+ else
+ {
+ throw new InvalidParameterException("unknown key size.");
+ }
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)params;
+ this.ecParams = params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof java.security.spec.ECParameterSpec)
+ {
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)params;
+ this.ecParams = params;
+
+ ECCurve curve = EC5Util.convertCurve(p.getCurve());
+ ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveGenParameterSpec)
+ {
+ String curveName;
+
+ if (params instanceof ECGenParameterSpec)
+ {
+ curveName = ((ECGenParameterSpec)params).getName();
+ }
+ else
+ {
+ curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+ }
+
+ //ECDomainParameters ecP = ECGOST3410NamedCurves.getByName(curveName);
+ ECDomainParameters ecP = DSTU4145NamedCurves.getByOID(new ASN1ObjectIdentifier(curveName));
+ if (ecP == null)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+ }
+
+ this.ecParams = new ECNamedCurveSpec(
+ curveName,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+ ECCurve curve = EC5Util.convertCurve(p.getCurve());
+ ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() != null)
+ {
+ ECParameterSpec p = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ this.ecParams = params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() == null)
+ {
+ throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec: " + params.getClass().getName());
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException("DSTU Key Pair Generator not initialised");
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ if (ecParams instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)ecParams;
+
+ BCDSTU4145PublicKey pubKey = new BCDSTU4145PublicKey(algorithm, pub, p);
+ return new KeyPair(pubKey,
+ new BCDSTU4145PrivateKey(algorithm, priv, pubKey, p));
+ }
+ else if (ecParams == null)
+ {
+ return new KeyPair(new BCDSTU4145PublicKey(algorithm, pub),
+ new BCDSTU4145PrivateKey(algorithm, priv));
+ }
+ else
+ {
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+ BCDSTU4145PublicKey pubKey = new BCDSTU4145PublicKey(algorithm, pub, p);
+
+ return new KeyPair(pubKey, new BCDSTU4145PrivateKey(algorithm, priv, pubKey, p));
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java
new file mode 100644
index 000000000..a6256281d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java
@@ -0,0 +1,221 @@
+package org.spongycastle.jcajce.provider.asymmetric.dstu;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.DSTU4145Signer;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class SignatureSpi
+ extends java.security.SignatureSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+
+ private static byte[] DEFAULT_SBOX = {
+ 0xa, 0x9, 0xd, 0x6, 0xe, 0xb, 0x4, 0x5, 0xf, 0x1, 0x3, 0xc, 0x7, 0x0, 0x8, 0x2,
+ 0x8, 0x0, 0xc, 0x4, 0x9, 0x6, 0x7, 0xb, 0x2, 0x3, 0x1, 0xf, 0x5, 0xe, 0xa, 0xd,
+ 0xf, 0x6, 0x5, 0x8, 0xe, 0xb, 0xa, 0x4, 0xc, 0x0, 0x3, 0x7, 0x2, 0x9, 0x1, 0xd,
+ 0x3, 0x8, 0xd, 0x9, 0x6, 0xb, 0xf, 0x0, 0x2, 0x5, 0xc, 0xa, 0x4, 0xe, 0x1, 0x7,
+ 0xf, 0x8, 0xe, 0x9, 0x7, 0x2, 0x0, 0xd, 0xc, 0x6, 0x1, 0x5, 0xb, 0x4, 0x3, 0xa,
+ 0x2, 0x8, 0x9, 0x7, 0x5, 0xf, 0x0, 0xb, 0xc, 0x1, 0xd, 0xe, 0xa, 0x3, 0x6, 0x4,
+ 0x3, 0x8, 0xb, 0x5, 0x6, 0x4, 0xe, 0xa, 0x2, 0xc, 0x1, 0x7, 0x9, 0xf, 0xd, 0x0,
+ 0x1, 0x2, 0x3, 0xe, 0x6, 0xd, 0xb, 0x8, 0xf, 0xa, 0xc, 0x5, 0x7, 0x9, 0x0, 0x4
+ };
+
+ public SignatureSpi()
+ {
+ //TODO: Add default ua s-box
+ //this.digest = new GOST3411Digest(DEFAULT_SBOX);
+ this.signer = new DSTU4145Signer();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest = new GOST3411Digest(expandSbox(((BCDSTU4145PublicKey)publicKey).getSbox()));
+ signer.init(false, param);
+ }
+
+ byte[] expandSbox(byte[] compressed)
+ {
+ byte[] expanded = new byte[128];
+
+ for (int i = 0; i < compressed.length; i++)
+ {
+ expanded[i * 2] = (byte)((compressed[i] >> 4) & 0xf);
+ expanded[i * 2 + 1] = (byte)(compressed[i] & 0xf);
+ }
+ return expanded;
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = null;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+
+ digest = new GOST3411Digest(DEFAULT_SBOX);
+
+ if (appRandom != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, appRandom));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+ byte[] r = sig[0].toByteArray();
+ byte[] s = sig[1].toByteArray();
+
+ byte[] sigBytes = new byte[(r.length > s.length ? r.length * 2 : s.length * 2)];
+ System.arraycopy(s, 0, sigBytes, (sigBytes.length / 2) - s.length, s.length);
+ System.arraycopy(r, 0, sigBytes, sigBytes.length - r.length, r.length);
+
+ return new DEROctetString(sigBytes).getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ byte[] bytes = ((ASN1OctetString)ASN1OctetString.fromByteArray(sigBytes)).getOctets();
+
+ byte[] r = new byte[bytes.length / 2];
+ byte[] s = new byte[bytes.length / 2];
+
+ System.arraycopy(bytes, 0, s, 0, bytes.length / 2);
+
+ System.arraycopy(bytes, bytes.length / 2, r, 0, bytes.length / 2);
+
+ sig = new BigInteger[2];
+ sig[0] = new BigInteger(1, r);
+ sig[1] = new BigInteger(1, s);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/SignatureSpiLe.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/SignatureSpiLe.java
new file mode 100644
index 000000000..1b83d55e0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/dstu/SignatureSpiLe.java
@@ -0,0 +1,69 @@
+package org.spongycastle.jcajce.provider.asymmetric.dstu;
+
+import java.io.IOException;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+
+public class SignatureSpiLe
+ extends SignatureSpi
+{
+ void reverseBytes(byte[] bytes)
+ {
+ byte tmp;
+
+ for (int i = 0; i < bytes.length / 2; i++)
+ {
+ tmp = bytes[i];
+ bytes[i] = bytes[bytes.length - 1 - i];
+ bytes[bytes.length - 1 - i] = tmp;
+ }
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] signature = ASN1OctetString.getInstance(super.engineSign()).getOctets();
+ reverseBytes(signature);
+ try
+ {
+ return (new DEROctetString(signature)).getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] bytes = null;
+
+ try
+ {
+ bytes = ((ASN1OctetString)ASN1OctetString.fromByteArray(sigBytes)).getOctets();
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ reverseBytes(bytes);
+
+ try
+ {
+ return super.engineVerify((new DEROctetString(bytes)).getEncoded());
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
new file mode 100644
index 000000000..451b4b688
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
@@ -0,0 +1,462 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class BCECPrivateKey
+ implements ECPrivateKey, org.spongycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ static final long serialVersionUID = 994553197664784084L;
+
+ private String algorithm = "EC";
+ private boolean withCompression;
+
+ private transient BigInteger d;
+ private transient ECParameterSpec ecSpec;
+ private transient ProviderConfiguration configuration;
+ private transient DERBitString publicKey;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCECPrivateKey()
+ {
+ }
+
+ public BCECPrivateKey(
+ ECPrivateKey key,
+ ProviderConfiguration configuration)
+ {
+ this.d = key.getS();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ org.spongycastle.jce.spec.ECPrivateKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getD();
+
+ if (spec.getParams() != null) // can be null if implicitlyCA
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve;
+
+ ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ this.ecSpec = null;
+ }
+
+ this.configuration = configuration;
+ }
+
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getS();
+ this.ecSpec = spec.getParams();
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ BCECPrivateKey key)
+ {
+ this.algorithm = algorithm;
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.attrCarrier = key.attrCarrier;
+ this.publicKey = key.publicKey;
+ this.configuration = key.configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECPublicKey pubKey,
+ ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.configuration = configuration;
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECPublicKey pubKey,
+ org.spongycastle.jce.spec.ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.configuration = configuration;
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ this.configuration = configuration;
+ }
+
+ BCECPrivateKey(
+ String algorithm,
+ PrivateKeyInfo info,
+ ProviderConfiguration configuration)
+ throws IOException
+ {
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ populateFromPrivKeyInfo(info);
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ throws IOException
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECUtil.getCurveName(oid),
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ ASN1Encodable privKey = info.parsePrivateKey();
+ if (privKey instanceof ASN1Integer)
+ {
+ ASN1Integer derD = ASN1Integer.getInstance(privKey);
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ org.spongycastle.asn1.sec.ECPrivateKey ec = org.spongycastle.asn1.sec.ECPrivateKey.getInstance(privKey);
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ X962Parameters params;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null) // guess it's the OID
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ org.spongycastle.asn1.sec.ECPrivateKey keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new org.spongycastle.asn1.sec.ECPrivateKey(this.getS(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new org.spongycastle.asn1.sec.ECPrivateKey(this.getS(), params);
+ }
+
+ try
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure);
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.spongycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null)
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return configuration.getEcImplicitlyCa();
+ }
+
+ public BigInteger getS()
+ {
+ return d;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECPrivateKey))
+ {
+ return false;
+ }
+
+ BCECPrivateKey other = (BCECPrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Private Key").append(nl);
+ buf.append(" S: ").append(this.d.toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ private DERBitString getPublicKeyDetails(BCECPublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
new file mode 100644
index 000000000..d1bc1d800
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
@@ -0,0 +1,456 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ECPoint;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class BCECPublicKey
+ implements ECPublicKey, org.spongycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+ static final long serialVersionUID = 2422789860422731812L;
+
+ private String algorithm = "EC";
+ private boolean withCompression;
+
+ private transient org.spongycastle.math.ec.ECPoint q;
+ private transient ECParameterSpec ecSpec;
+ private transient ProviderConfiguration configuration;
+
+ public BCECPublicKey(
+ String algorithm,
+ BCECPublicKey key)
+ {
+ this.algorithm = algorithm;
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.configuration = key.configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.ecSpec = spec.getParams();
+ this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ this.configuration = configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ org.spongycastle.jce.spec.ECPublicKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = spec.getQ();
+
+ if (spec.getParams() != null) // can be null if implictlyCa
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.spongycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getXCoord().toBigInteger(), q.getYCoord().toBigInteger(), false);
+ }
+ this.ecSpec = null;
+ }
+
+ this.configuration = configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ this.configuration = configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ org.spongycastle.jce.spec.ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+ }
+
+ this.configuration = configuration;
+ }
+
+ /*
+ * called for implicitCA
+ */
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ this.configuration = configuration;
+ }
+
+ public BCECPublicKey(
+ ECPublicKey key,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+ }
+
+ BCECPublicKey(
+ String algorithm,
+ SubjectPublicKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ populateFromPubKeyInfo(info);
+ }
+
+ private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+ {
+ return new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithm().getParameters());
+ ECCurve curve;
+ EllipticCurve ellipticCurve;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ curve = ecP.getCurve();
+ ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECUtil.getCurveName(oid),
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ curve = configuration.getEcImplicitlyCa().getCurve();
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+
+ curve = ecP.getCurve();
+ ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ DERBitString bits = info.getPublicKeyData();
+ byte[] data = bits.getBytes();
+ ASN1OctetString key = new DEROctetString(data);
+
+ //
+ // extra octet string - one of our old certs...
+ //
+ if (data[0] == 0x04 && data[1] == data.length - 2
+ && (data[2] == 0x02 || data[2] == 0x03))
+ {
+ int qLength = new X9IntegerConverter().getByteLength(curve);
+
+ if (qLength >= data.length - 3)
+ {
+ try
+ {
+ key = (ASN1OctetString) ASN1Primitive.fromByteArray(data);
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+ }
+ X9ECPoint derQ = new X9ECPoint(curve, key);
+
+ this.q = derQ.getPoint();
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ ASN1Encodable params;
+ SubjectPublicKeyInfo info;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null)
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECCurve curve = this.engineGetQ().getCurve();
+ ASN1OctetString p;
+
+ // stored curve is null if ImplicitlyCa
+ if (ecSpec == null)
+ {
+ p = (ASN1OctetString)
+ new X9ECPoint(curve.createPoint(this.getQ().getXCoord().toBigInteger(), this.getQ().getYCoord().toBigInteger(), withCompression)).toASN1Primitive();
+ }
+ else
+ {
+ p = (ASN1OctetString)
+ new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive();
+ }
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+ {
+ byte[] val = bI.toByteArray();
+ if (val.length < 32)
+ {
+ byte[] tmp = new byte[32];
+ System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+ val = tmp;
+ }
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[offSet + i] = val[val.length - 1 - i];
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.spongycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null) // implictlyCA
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ public ECPoint getW()
+ {
+ return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
+ }
+
+ public org.spongycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.spongycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.spongycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord());
+ }
+ else
+ {
+ return new org.spongycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord());
+ }
+ }
+
+ return q;
+ }
+
+ public org.spongycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return configuration.getEcImplicitlyCa();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECPublicKey))
+ {
+ return false;
+ }
+
+ BCECPublicKey other = (BCECPublicKey)o;
+
+ return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/IESCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/IESCipher.java
new file mode 100644
index 000000000..39baf08ff
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/IESCipher.java
@@ -0,0 +1,501 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+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;
+
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.KeyEncoder;
+import org.spongycastle.crypto.agreement.ECDHBasicAgreement;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.engines.AESEngine;
+import org.spongycastle.crypto.engines.DESedeEngine;
+import org.spongycastle.crypto.engines.IESEngine;
+import org.spongycastle.crypto.generators.ECKeyPairGenerator;
+import org.spongycastle.crypto.generators.EphemeralKeyPairGenerator;
+import org.spongycastle.crypto.generators.KDF2BytesGenerator;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECKeyGenerationParameters;
+import org.spongycastle.crypto.params.ECKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.crypto.params.IESParameters;
+import org.spongycastle.crypto.params.IESWithCipherParameters;
+import org.spongycastle.crypto.parsers.ECIESPublicKeyParser;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.IESUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.IESKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.IESParameterSpec;
+import org.spongycastle.util.Strings;
+
+
+public class IESCipher
+ extends CipherSpi
+{
+ private IESEngine engine;
+ private int state = -1;
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ private AlgorithmParameters engineParam = null;
+ private IESParameterSpec engineSpec = null;
+ private AsymmetricKeyParameter key;
+ private SecureRandom random;
+ private boolean dhaesMode = false;
+ private AsymmetricKeyParameter otherKeyParameter = null;
+
+ public IESCipher(IESEngine engine)
+ {
+ this.engine = engine;
+ }
+
+
+ public int engineGetBlockSize()
+ {
+ if (engine.getCipher() != null)
+ {
+ return engine.getCipher().getBlockSize();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+
+ public int engineGetKeySize(Key key)
+ {
+ if (key instanceof ECKey)
+ {
+ return ((ECKey)key).getParameters().getCurve().getFieldSize();
+ }
+ else
+ {
+ throw new IllegalArgumentException("not an EC key");
+ }
+ }
+
+
+ public byte[] engineGetIV()
+ {
+ return null;
+ }
+
+
+ public AlgorithmParameters engineGetParameters()
+ {
+ if (engineParam == null && engineSpec != null)
+ {
+ try
+ {
+ engineParam = AlgorithmParameters.getInstance("IES", BouncyCastleProvider.PROVIDER_NAME);
+ engineParam.init(engineSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ return engineParam;
+ }
+
+
+ public void engineSetMode(String mode)
+ throws NoSuchAlgorithmException
+ {
+ String modeName = Strings.toUpperCase(mode);
+
+ if (modeName.equals("NONE"))
+ {
+ dhaesMode = false;
+ }
+ else if (modeName.equals("DHAES"))
+ {
+ dhaesMode = true;
+ }
+ else
+ {
+ throw new IllegalArgumentException("can't support mode " + mode);
+ }
+ }
+
+
+ public int engineGetOutputSize(int inputLen)
+ {
+ int len1, len2, len3;
+
+ len1 = engine.getMac().getMacSize();
+
+ if (key != null)
+ {
+ len2 = 1 + 2 * (((ECKey)key).getParameters().getCurve().getFieldSize() + 7) / 8;
+ }
+ else
+ {
+ throw new IllegalStateException("cipher not initialised");
+ }
+
+ if (engine.getCipher() == null)
+ {
+ len3 = inputLen;
+ }
+ else if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ len3 = engine.getCipher().getOutputSize(inputLen);
+ }
+ else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
+ {
+ len3 = engine.getCipher().getOutputSize(inputLen - len1 - len2);
+ }
+ else
+ {
+ throw new IllegalStateException("cipher not initialised");
+ }
+
+ if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ return buffer.size() + len1 + len2 + len3;
+ }
+ else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
+ {
+ return buffer.size() - len1 - len2 + len3;
+ }
+ else
+ {
+ throw new IllegalStateException("cipher not initialised");
+ }
+
+ }
+
+ public void engineSetPadding(String padding)
+ throws NoSuchPaddingException
+ {
+ String paddingName = Strings.toUpperCase(padding);
+
+ // TDOD: make this meaningful...
+ if (paddingName.equals("NOPADDING"))
+ {
+
+ }
+ else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+ {
+
+ }
+ else
+ {
+ throw new NoSuchPaddingException("padding not available with IESCipher");
+ }
+ }
+
+
+ // Initialisation methods
+
+ public void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(IESParameterSpec.class);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString());
+ }
+ }
+
+ engineParam = params;
+ engineInit(opmode, key, paramSpec, random);
+
+ }
+
+
+ public void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec engineSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException, InvalidKeyException
+ {
+ otherKeyParameter = null;
+
+ // Use default parameters (including cipher key size) if none are specified
+ if (engineSpec == null)
+ {
+ this.engineSpec = IESUtil.guessParameterSpec(engine);
+ }
+ else if (engineSpec instanceof IESParameterSpec)
+ {
+ this.engineSpec = (IESParameterSpec)engineSpec;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("must be passed IES parameters");
+ }
+
+ // Parse the recipient's key
+ if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)
+ {
+ if (key instanceof ECPublicKey)
+ {
+ this.key = ECUtil.generatePublicKeyParameter((PublicKey)key);
+ }
+ else if (key instanceof IESKey)
+ {
+ IESKey ieKey = (IESKey)key;
+
+ this.key = ECUtil.generatePublicKeyParameter(ieKey.getPublic());
+ this.otherKeyParameter = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate());
+ }
+ else
+ {
+ throw new InvalidKeyException("must be passed recipient's public EC key for encryption");
+ }
+ }
+ else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE)
+ {
+ if (key instanceof ECPrivateKey)
+ {
+ this.key = ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+ }
+ else if (key instanceof IESKey)
+ {
+ IESKey ieKey = (IESKey)key;
+
+ this.otherKeyParameter = ECUtil.generatePublicKeyParameter(ieKey.getPublic());
+ this.key = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate());
+ }
+ else
+ {
+ throw new InvalidKeyException("must be passed recipient's private EC key for decryption");
+ }
+ }
+ else
+ {
+ throw new InvalidKeyException("must be passed EC key");
+ }
+
+
+ this.random = random;
+ this.state = opmode;
+ buffer.reset();
+
+ }
+
+
+ public void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new IllegalArgumentException("can't handle supplied parameter spec");
+ }
+
+ }
+
+
+ // Update methods - buffer the input
+
+ public byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ return null;
+ }
+
+
+ public int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ return 0;
+ }
+
+
+ // Finalisation methods
+
+ public byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (inputLen != 0)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ }
+
+ final byte[] in = buffer.toByteArray();
+ buffer.reset();
+
+ // Convert parameters for use in IESEngine
+ IESParameters params = new IESWithCipherParameters(engineSpec.getDerivationV(),
+ engineSpec.getEncodingV(),
+ engineSpec.getMacKeySize(),
+ engineSpec.getCipherKeySize());
+
+ final ECDomainParameters ecParams = ((ECKeyParameters)key).getParameters();
+
+ final byte[] V;
+
+ if (otherKeyParameter != null)
+ {
+ try
+ {
+ if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ engine.init(true, otherKeyParameter, key, params);
+ }
+ else
+ {
+ engine.init(false, key, otherKeyParameter, params);
+ }
+ return engine.processBlock(in, 0, in.length);
+ }
+ catch (Exception e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ // Generate the ephemeral key pair
+ ECKeyPairGenerator gen = new ECKeyPairGenerator();
+ gen.init(new ECKeyGenerationParameters(ecParams, random));
+
+ EphemeralKeyPairGenerator kGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder()
+ {
+ public byte[] getEncoded(AsymmetricKeyParameter keyParameter)
+ {
+ return ((ECPublicKeyParameters)keyParameter).getQ().getEncoded();
+ }
+ });
+
+ // Encrypt the buffer
+ try
+ {
+ engine.init(key, params, kGen);
+
+ return engine.processBlock(in, 0, in.length);
+ }
+ catch (Exception e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ }
+ else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
+ {
+ // Decrypt the buffer
+ try
+ {
+ engine.init(key, params, new ECIESPublicKeyParser(ecParams));
+
+ return engine.processBlock(in, 0, in.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+ else
+ {
+ throw new IllegalStateException("cipher not initialised");
+ }
+
+ }
+
+ public int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLength,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
+ {
+
+ byte[] buf = engineDoFinal(input, inputOffset, inputLength);
+ System.arraycopy(buf, 0, output, outputOffset, buf.length);
+ return buf.length;
+ }
+
+
+ /**
+ * Classes that inherit from us
+ */
+
+ static public class ECIES
+ extends IESCipher
+ {
+ public ECIES()
+ {
+ super(new IESEngine(new ECDHBasicAgreement(),
+ new KDF2BytesGenerator(new SHA1Digest()),
+ new HMac(new SHA1Digest())));
+ }
+ }
+
+ static public class ECIESwithDESede
+ extends IESCipher
+ {
+ public ECIESwithDESede()
+ {
+ super(new IESEngine(new ECDHBasicAgreement(),
+ new KDF2BytesGenerator(new SHA1Digest()),
+ new HMac(new SHA1Digest()),
+ new PaddedBufferedBlockCipher(new DESedeEngine())));
+ }
+ }
+
+ static public class ECIESwithAES
+ extends IESCipher
+ {
+ public ECIESwithAES()
+ {
+ super(new IESEngine(new ECDHBasicAgreement(),
+ new KDF2BytesGenerator(new SHA1Digest()),
+ new HMac(new SHA1Digest()),
+ new PaddedBufferedBlockCipher(new AESEngine())));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
new file mode 100644
index 000000000..5ddee864c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -0,0 +1,317 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.crypto.BasicAgreement;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DerivationFunction;
+import org.spongycastle.crypto.agreement.ECDHBasicAgreement;
+import org.spongycastle.crypto.agreement.ECDHCBasicAgreement;
+import org.spongycastle.crypto.agreement.ECMQVBasicAgreement;
+import org.spongycastle.crypto.agreement.kdf.DHKDFParameters;
+import org.spongycastle.crypto.agreement.kdf.ECDHKEKGenerator;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.crypto.params.MQVPrivateParameters;
+import org.spongycastle.crypto.params.MQVPublicParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.MQVPrivateKey;
+import org.spongycastle.jce.interfaces.MQVPublicKey;
+import org.spongycastle.util.Integers;
+
+/**
+ * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+ * both the simple one, and the simple one with cofactors are supported.
+ *
+ * Also, MQV key agreement per SEC-1
+ */
+public class KeyAgreementSpi
+ extends javax.crypto.KeyAgreementSpi
+{
+ private static final X9IntegerConverter converter = new X9IntegerConverter();
+ private static final Hashtable algorithms = new Hashtable();
+
+ static
+ {
+ Integer i128 = Integers.valueOf(128);
+ Integer i192 = Integers.valueOf(192);
+ Integer i256 = Integers.valueOf(256);
+
+ algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
+ algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
+ algorithms.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
+ algorithms.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
+ algorithms.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
+ algorithms.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
+ algorithms.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
+ }
+
+ private String kaAlgorithm;
+ private BigInteger result;
+ private ECDomainParameters parameters;
+ private BasicAgreement agreement;
+ private DerivationFunction kdf;
+
+ private byte[] bigIntToBytes(
+ BigInteger r)
+ {
+ return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getAffineXCoord()));
+ }
+
+ protected KeyAgreementSpi(
+ String kaAlgorithm,
+ BasicAgreement agreement,
+ DerivationFunction kdf)
+ {
+ this.kaAlgorithm = kaAlgorithm;
+ this.agreement = agreement;
+ this.kdf = kdf;
+ }
+
+ protected Key engineDoPhase(
+ Key key,
+ boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ if (parameters == null)
+ {
+ throw new IllegalStateException(kaAlgorithm + " not initialised.");
+ }
+
+ if (!lastPhase)
+ {
+ throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
+ }
+
+ CipherParameters pubKey;
+ if (agreement instanceof ECMQVBasicAgreement)
+ {
+ if (!(key instanceof MQVPublicKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(MQVPublicKey.class) + " for doPhase");
+ }
+
+ MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+ ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+ ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+
+ pubKey = new MQVPublicParameters(staticKey, ephemKey);
+
+ // TODO Validate that all the keys are using the same parameters?
+ }
+ else
+ {
+ if (!(key instanceof PublicKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPublicKey.class) + " for doPhase");
+ }
+
+ pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key);
+
+ // TODO Validate that all the keys are using the same parameters?
+ }
+
+ result = agreement.calculateAgreement(pubKey);
+
+ return null;
+ }
+
+ protected byte[] engineGenerateSecret()
+ throws IllegalStateException
+ {
+ if (kdf != null)
+ {
+ throw new UnsupportedOperationException(
+ "KDF can only be used when algorithm is known");
+ }
+
+ return bigIntToBytes(result);
+ }
+
+ protected int engineGenerateSecret(
+ byte[] sharedSecret,
+ int offset)
+ throws IllegalStateException, ShortBufferException
+ {
+ byte[] secret = engineGenerateSecret();
+
+ if (sharedSecret.length - offset < secret.length)
+ {
+ throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
+ }
+
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+
+ return secret.length;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ byte[] secret = bigIntToBytes(result);
+
+ if (kdf != null)
+ {
+ if (!algorithms.containsKey(algorithm))
+ {
+ throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
+ }
+
+ int keySize = ((Integer)algorithms.get(algorithm)).intValue();
+
+ DHKDFParameters params = new DHKDFParameters(new ASN1ObjectIdentifier(algorithm), keySize, secret);
+
+ byte[] keyBytes = new byte[keySize / 8];
+ kdf.init(params);
+ kdf.generateBytes(keyBytes, 0, keyBytes.length);
+ secret = keyBytes;
+ }
+ else
+ {
+ // TODO Should we be ensuring the key is the right length?
+ }
+
+ return new SecretKeySpec(secret, algorithm);
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initFromKey(key);
+ }
+
+ protected void engineInit(
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ initFromKey(key);
+ }
+
+ private void initFromKey(Key key)
+ throws InvalidKeyException
+ {
+ if (agreement instanceof ECMQVBasicAgreement)
+ {
+ if (!(key instanceof MQVPrivateKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(MQVPrivateKey.class) + " for initialisation");
+ }
+
+ MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+ ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
+ ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+ ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
+ ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+
+ ECPublicKeyParameters ephemPubKey = null;
+ if (mqvPrivKey.getEphemeralPublicKey() != null)
+ {
+ ephemPubKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+ }
+
+ MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+ this.parameters = staticPrivKey.getParameters();
+
+ // TODO Validate that all the keys are using the same parameters?
+
+ agreement.init(localParams);
+ }
+ else
+ {
+ if (!(key instanceof PrivateKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPrivateKey.class) + " for initialisation");
+ }
+
+ ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+ this.parameters = privKey.getParameters();
+
+ agreement.init(privKey);
+ }
+ }
+
+ private static String getSimpleName(Class clazz)
+ {
+ String fullName = clazz.getName();
+
+ return fullName.substring(fullName.lastIndexOf('.') + 1);
+ }
+
+ public static class DH
+ extends KeyAgreementSpi
+ {
+ public DH()
+ {
+ super("ECDH", new ECDHBasicAgreement(), null);
+ }
+ }
+
+ public static class DHC
+ extends KeyAgreementSpi
+ {
+ public DHC()
+ {
+ super("ECDHC", new ECDHCBasicAgreement(), null);
+ }
+ }
+
+ public static class MQV
+ extends KeyAgreementSpi
+ {
+ public MQV()
+ {
+ super("ECMQV", new ECMQVBasicAgreement(), null);
+ }
+ }
+
+ public static class DHwithSHA1KDF
+ extends KeyAgreementSpi
+ {
+ public DHwithSHA1KDF()
+ {
+ super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ }
+ }
+
+ public static class MQVwithSHA1KDF
+ extends KeyAgreementSpi
+ {
+ public MQVwithSHA1KDF()
+ {
+ super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
new file mode 100644
index 000000000..5e77a74ca
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
@@ -0,0 +1,239 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ String algorithm;
+ ProviderConfiguration configuration;
+
+ KeyFactorySpi(
+ String algorithm,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPublicKey)
+ {
+ return new BCECPublicKey((ECPublicKey)key, configuration);
+ }
+ else if (key instanceof ECPrivateKey)
+ {
+ return new BCECPrivateKey((ECPrivateKey)key, configuration);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+ }
+ }
+ else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false));
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec);
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false));
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec);
+ }
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPrivateKeySpec)
+ {
+ return new BCECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec, configuration);
+ }
+ else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
+ {
+ return new BCECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec, configuration);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration);
+ }
+ else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+ {
+ return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ return new BCECPrivateKey(algorithm, keyInfo, configuration);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ return new BCECPublicKey(algorithm, keyInfo, configuration);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public static class EC
+ extends KeyFactorySpi
+ {
+ public EC()
+ {
+ super("EC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDSA
+ extends KeyFactorySpi
+ {
+ public ECDSA()
+ {
+ super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECGOST3410
+ extends KeyFactorySpi
+ {
+ public ECGOST3410()
+ {
+ super("ECGOST3410", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDH
+ extends KeyFactorySpi
+ {
+ public ECDH()
+ {
+ super("ECDH", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDHC
+ extends KeyFactorySpi
+ {
+ public ECDHC()
+ {
+ super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECMQV
+ extends KeyFactorySpi
+ {
+ public ECMQV()
+ {
+ super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..dec8acd9a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
@@ -0,0 +1,275 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Hashtable;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x9.ECNamedCurveTable;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.ECKeyPairGenerator;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECKeyGenerationParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+import org.spongycastle.util.Integers;
+
+public abstract class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ public KeyPairGeneratorSpi(String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ public static class EC
+ extends KeyPairGeneratorSpi
+ {
+ ECKeyGenerationParameters param;
+ ECKeyPairGenerator engine = new ECKeyPairGenerator();
+ Object ecParams = null;
+ int strength = 239;
+ int certainty = 50;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+ String algorithm;
+ ProviderConfiguration configuration;
+
+ static private Hashtable ecParameters;
+
+ static {
+ ecParameters = new Hashtable();
+
+ ecParameters.put(Integers.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
+ ecParameters.put(Integers.valueOf(239), new ECGenParameterSpec("prime239v1"));
+ ecParameters.put(Integers.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
+
+ ecParameters.put(Integers.valueOf(224), new ECGenParameterSpec("P-224"));
+ ecParameters.put(Integers.valueOf(384), new ECGenParameterSpec("P-384"));
+ ecParameters.put(Integers.valueOf(521), new ECGenParameterSpec("P-521"));
+ }
+
+ public EC()
+ {
+ super("EC");
+ this.algorithm = "EC";
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ }
+
+ public EC(
+ String algorithm,
+ ProviderConfiguration configuration)
+ {
+ super(algorithm);
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integers.valueOf(strength));
+
+ if (ecParams != null)
+ {
+ try
+ {
+ initialize(ecParams, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException("key size not configurable.");
+ }
+ }
+ else
+ {
+ throw new InvalidParameterException("unknown key size.");
+ }
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)params;
+ this.ecParams = params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof java.security.spec.ECParameterSpec)
+ {
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)params;
+ this.ecParams = params;
+
+ ECCurve curve = EC5Util.convertCurve(p.getCurve());
+ ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveGenParameterSpec)
+ {
+ String curveName;
+
+ if (params instanceof ECGenParameterSpec)
+ {
+ curveName = ((ECGenParameterSpec)params).getName();
+ }
+ else
+ {
+ curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+ }
+
+ X9ECParameters ecP = ECNamedCurveTable.getByName(curveName);
+ if (ecP == null)
+ {
+ // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
+ try
+ {
+ ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName);
+ ecP = ECNamedCurveTable.getByOID(oid);
+ if (ecP == null)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+ }
+ }
+
+ this.ecParams = new ECNamedCurveSpec(
+ curveName,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ null); // ecP.getSeed()); Work-around JDK bug -- it won't look up named curves properly if seed is present
+
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+ ECCurve curve = EC5Util.convertCurve(p.getCurve());
+ ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && configuration.getEcImplicitlyCa() != null)
+ {
+ ECParameterSpec p = configuration.getEcImplicitlyCa();
+ this.ecParams = params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && configuration.getEcImplicitlyCa() == null)
+ {
+ throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ initialize(strength, new SecureRandom());
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ if (ecParams instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)ecParams;
+
+ BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
+ return new KeyPair(pubKey,
+ new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
+ }
+ else if (ecParams == null)
+ {
+ return new KeyPair(new BCECPublicKey(algorithm, pub, configuration),
+ new BCECPrivateKey(algorithm, priv, configuration));
+ }
+ else
+ {
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+ BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
+
+ return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
+ }
+ }
+ }
+
+ public static class ECDSA
+ extends EC
+ {
+ public ECDSA()
+ {
+ super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDH
+ extends EC
+ {
+ public ECDH()
+ {
+ super("ECDH", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDHC
+ extends EC
+ {
+ public ECDHC()
+ {
+ super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECMQV
+ extends EC
+ {
+ public ECMQV()
+ {
+ super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
new file mode 100644
index 000000000..9f1a766e9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -0,0 +1,358 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.NullDigest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.ECDSASigner;
+import org.spongycastle.crypto.signers.ECNRSigner;
+import org.spongycastle.crypto.signers.HMacDSAKCalculator;
+import org.spongycastle.jcajce.provider.asymmetric.util.DSABase;
+import org.spongycastle.jcajce.provider.asymmetric.util.DSAEncoder;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+
+public class SignatureSpi
+ extends DSABase
+{
+ SignatureSpi(Digest digest, DSA signer, DSAEncoder encoder)
+ {
+ super(digest, signer, encoder);
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = ECUtil.generatePublicKeyParameter(publicKey);
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = ECUtil.generatePrivateKeyParameter(privateKey);
+
+ digest.reset();
+
+ if (appRandom != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, appRandom));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ static public class ecDSA
+ extends SignatureSpi
+ {
+ public ecDSA()
+ {
+ super(new SHA1Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSA
+ extends SignatureSpi
+ {
+ public ecDetDSA()
+ {
+ super(new SHA1Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA1Digest())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSAnone
+ extends SignatureSpi
+ {
+ public ecDSAnone()
+ {
+ super(new NullDigest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA224
+ extends SignatureSpi
+ {
+ public ecDSA224()
+ {
+ super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSA224
+ extends SignatureSpi
+ {
+ public ecDetDSA224()
+ {
+ super(new SHA224Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA224Digest())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA256
+ extends SignatureSpi
+ {
+ public ecDSA256()
+ {
+ super(new SHA256Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSA256
+ extends SignatureSpi
+ {
+ public ecDetDSA256()
+ {
+ super(new SHA256Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA384
+ extends SignatureSpi
+ {
+ public ecDSA384()
+ {
+ super(new SHA384Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSA384
+ extends SignatureSpi
+ {
+ public ecDetDSA384()
+ {
+ super(new SHA384Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA384Digest())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA512
+ extends SignatureSpi
+ {
+ public ecDSA512()
+ {
+ super(new SHA512Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDetDSA512
+ extends SignatureSpi
+ {
+ public ecDetDSA512()
+ {
+ super(new SHA512Digest(), new ECDSASigner(new HMacDSAKCalculator(new SHA512Digest())), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSARipeMD160
+ extends SignatureSpi
+ {
+ public ecDSARipeMD160()
+ {
+ super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR
+ extends SignatureSpi
+ {
+ public ecNR()
+ {
+ super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR224
+ extends SignatureSpi
+ {
+ public ecNR224()
+ {
+ super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR256
+ extends SignatureSpi
+ {
+ public ecNR256()
+ {
+ super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR384
+ extends SignatureSpi
+ {
+ public ecNR384()
+ {
+ super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR512
+ extends SignatureSpi
+ {
+ public ecNR512()
+ {
+ super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA
+ extends SignatureSpi
+ {
+ public ecCVCDSA()
+ {
+ super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA224
+ extends SignatureSpi
+ {
+ public ecCVCDSA224()
+ {
+ super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA256
+ extends SignatureSpi
+ {
+ public ecCVCDSA256()
+ {
+ super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA384
+ extends SignatureSpi
+ {
+ public ecCVCDSA384()
+ {
+ super(new SHA384Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA512
+ extends SignatureSpi
+ {
+ public ecCVCDSA512()
+ {
+ super(new SHA512Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ private static class StdDSAEncoder
+ implements DSAEncoder
+ {
+ public byte[] encode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(r));
+ v.add(new ASN1Integer(s));
+
+ return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+ }
+
+ public BigInteger[] decode(
+ byte[] encoding)
+ throws IOException
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ BigInteger[] sig = new BigInteger[2];
+
+ sig[0] = ASN1Integer.getInstance(s.getObjectAt(0)).getValue();
+ sig[1] = ASN1Integer.getInstance(s.getObjectAt(1)).getValue();
+
+ return sig;
+ }
+ }
+
+ private static class CVCDSAEncoder
+ implements DSAEncoder
+ {
+ public byte[] encode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ byte[] first = makeUnsigned(r);
+ byte[] second = makeUnsigned(s);
+ byte[] res;
+
+ if (first.length > second.length)
+ {
+ res = new byte[first.length * 2];
+ }
+ else
+ {
+ res = new byte[second.length * 2];
+ }
+
+ System.arraycopy(first, 0, res, res.length / 2 - first.length, first.length);
+ System.arraycopy(second, 0, res, res.length - second.length, second.length);
+
+ return res;
+ }
+
+
+ private byte[] makeUnsigned(BigInteger val)
+ {
+ byte[] res = val.toByteArray();
+
+ if (res[0] == 0)
+ {
+ byte[] tmp = new byte[res.length - 1];
+
+ System.arraycopy(res, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return res;
+ }
+
+ public BigInteger[] decode(
+ byte[] encoding)
+ throws IOException
+ {
+ BigInteger[] sig = new BigInteger[2];
+
+ byte[] first = new byte[encoding.length / 2];
+ byte[] second = new byte[encoding.length / 2];
+
+ System.arraycopy(encoding, 0, first, 0, first.length);
+ System.arraycopy(encoding, first.length, second, 0, second.length);
+
+ sig[0] = new BigInteger(1, first);
+ sig[1] = new BigInteger(1, second);
+
+ return sig;
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
new file mode 100644
index 000000000..4e2297932
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
@@ -0,0 +1,542 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class BCECGOST3410PrivateKey
+ implements ECPrivateKey, org.spongycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ static final long serialVersionUID = 7245981689601667138L;
+
+ private String algorithm = "ECGOST3410";
+ private boolean withCompression;
+
+ private transient GOST3410PublicKeyAlgParameters gostParams;
+ private transient BigInteger d;
+ private transient ECParameterSpec ecSpec;
+ private transient DERBitString publicKey;
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCECGOST3410PrivateKey()
+ {
+ }
+
+ public BCECGOST3410PrivateKey(
+ ECPrivateKey key)
+ {
+ this.d = key.getS();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ }
+
+ public BCECGOST3410PrivateKey(
+ org.spongycastle.jce.spec.ECPrivateKeySpec spec)
+ {
+ this.d = spec.getD();
+
+ if (spec.getParams() != null) // can be null if implicitlyCA
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve;
+
+ ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ this.ecSpec = null;
+ }
+ }
+
+
+ public BCECGOST3410PrivateKey(
+ ECPrivateKeySpec spec)
+ {
+ this.d = spec.getS();
+ this.ecSpec = spec.getParams();
+ }
+
+ public BCECGOST3410PrivateKey(
+ BCECGOST3410PrivateKey key)
+ {
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.attrCarrier = key.attrCarrier;
+ this.publicKey = key.publicKey;
+ this.gostParams = key.gostParams;
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECGOST3410PublicKey pubKey,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ this.gostParams = pubKey.getGostParams();
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECGOST3410PublicKey pubKey,
+ org.spongycastle.jce.spec.ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(),
+ spec.getH().intValue());
+ }
+
+ this.gostParams = pubKey.getGostParams();
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ }
+
+ BCECGOST3410PrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ populateFromPrivKeyInfo(info);
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ throws IOException
+ {
+ ASN1Primitive p = info.getPrivateKeyAlgorithm().getParameters().toASN1Primitive();
+
+ if (p instanceof ASN1Sequence && (ASN1Sequence.getInstance(p).size() == 2 || ASN1Sequence.getInstance(p).size() == 3))
+ {
+ gostParams = GOST3410PublicKeyAlgParameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+
+ ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+
+ ECCurve curve = spec.getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(), spec.getH());
+
+ ASN1Encodable privKey = info.parsePrivateKey();
+
+ byte[] encVal = ASN1OctetString.getInstance(privKey).getOctets();
+ byte[] dVal = new byte[encVal.length];
+
+ for (int i = 0; i != encVal.length; i++)
+ {
+ dVal[i] = encVal[encVal.length - 1 - i];
+ }
+
+ this.d = new BigInteger(1, dVal);
+ }
+ else
+ {
+ // for backwards compatibility
+ X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ if (ecP == null) // GOST Curve
+ {
+ ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECGOST3410NamedCurves.getName(oid),
+ ellipticCurve,
+ new ECPoint(
+ gParam.getG().getAffineXCoord().toBigInteger(),
+ gParam.getG().getAffineYCoord().toBigInteger()),
+ gParam.getN(),
+ gParam.getH());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECUtil.getCurveName(oid),
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH());
+ }
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ ASN1Encodable privKey = info.parsePrivateKey();
+ if (privKey instanceof DERInteger)
+ {
+ DERInteger derD = DERInteger.getInstance(privKey);
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ org.spongycastle.asn1.sec.ECPrivateKey ec = org.spongycastle.asn1.sec.ECPrivateKey.getInstance(privKey);
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ if (gostParams != null)
+ {
+ byte[] encKey = new byte[32];
+
+ extractBytes(encKey, 0, this.getS());
+
+ try
+ {
+ PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, gostParams), new DEROctetString(encKey));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ X962Parameters params;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null) // guess it's the OID
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ org.spongycastle.asn1.sec.ECPrivateKey keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new org.spongycastle.asn1.sec.ECPrivateKey(this.getS(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new org.spongycastle.asn1.sec.ECPrivateKey(this.getS(), params);
+ }
+
+ try
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ }
+
+ private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+ {
+ byte[] val = bI.toByteArray();
+ if (val.length < 32)
+ {
+ byte[] tmp = new byte[32];
+ System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+ val = tmp;
+ }
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[offSet + i] = val[val.length - 1 - i];
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.spongycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null)
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public BigInteger getS()
+ {
+ return d;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECGOST3410PrivateKey))
+ {
+ return false;
+ }
+
+ BCECGOST3410PrivateKey other = (BCECGOST3410PrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Private Key").append(nl);
+ buf.append(" S: ").append(this.d.toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ private DERBitString getPublicKeyDetails(BCECGOST3410PublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
new file mode 100644
index 000000000..c0d10ebb7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
@@ -0,0 +1,405 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class BCECGOST3410PublicKey
+ implements ECPublicKey, org.spongycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+ static final long serialVersionUID = 7026240464295649314L;
+
+ private String algorithm = "ECGOST3410";
+ private boolean withCompression;
+
+ private transient org.spongycastle.math.ec.ECPoint q;
+ private transient ECParameterSpec ecSpec;
+ private transient GOST3410PublicKeyAlgParameters gostParams;
+
+ public BCECGOST3410PublicKey(
+ BCECGOST3410PublicKey key)
+ {
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.gostParams = key.gostParams;
+ }
+
+ public BCECGOST3410PublicKey(
+ ECPublicKeySpec spec)
+ {
+ this.ecSpec = spec.getParams();
+ this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ }
+
+ public BCECGOST3410PublicKey(
+ org.spongycastle.jce.spec.ECPublicKeySpec spec)
+ {
+ this.q = spec.getQ();
+
+ if (spec.getParams() != null) // can be null if implictlyCa
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.spongycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
+ }
+ this.ecSpec = null;
+ }
+ }
+
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+ }
+
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ org.spongycastle.jce.spec.ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+ }
+ }
+
+ /*
+ * called for implicitCA
+ */
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ }
+
+ private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+ {
+ return new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+
+ public BCECGOST3410PublicKey(
+ ECPublicKey key)
+ {
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+ }
+
+ BCECGOST3410PublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ populateFromPubKeyInfo(info);
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ DERBitString bits = info.getPublicKeyData();
+ ASN1OctetString key;
+ this.algorithm = "ECGOST3410";
+
+ try
+ {
+ key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes());
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+
+ byte[] keyEnc = key.getOctets();
+ byte[] x = new byte[32];
+ byte[] y = new byte[32];
+
+ for (int i = 0; i != x.length; i++)
+ {
+ x[i] = keyEnc[32 - 1 - i];
+ }
+
+ for (int i = 0; i != y.length; i++)
+ {
+ y[i] = keyEnc[64 - 1 - i];
+ }
+
+ gostParams = GOST3410PublicKeyAlgParameters.getInstance(info.getAlgorithm().getParameters());
+
+ ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+
+ ECCurve curve = spec.getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
+
+ this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y));
+
+ ecSpec = new ECNamedCurveSpec(
+ ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(), spec.getH());
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ ASN1Encodable params;
+ SubjectPublicKeyInfo info;
+
+ if (gostParams != null)
+ {
+ params = gostParams;
+ }
+ else
+ {
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ params = new GOST3410PublicKeyAlgParameters(
+ ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
+ CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
+ }
+ else
+ { // strictly speaking this may not be applicable...
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+ }
+
+ BigInteger bX = this.q.getAffineXCoord().toBigInteger();
+ BigInteger bY = this.q.getAffineYCoord().toBigInteger();
+ byte[] encKey = new byte[64];
+
+ extractBytes(encKey, 0, bX);
+ extractBytes(encKey, 32, bY);
+
+ try
+ {
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+ {
+ byte[] val = bI.toByteArray();
+ if (val.length < 32)
+ {
+ byte[] tmp = new byte[32];
+ System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+ val = tmp;
+ }
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[offSet + i] = val[val.length - 1 - i];
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.spongycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null) // implictlyCA
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ public ECPoint getW()
+ {
+ return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
+ }
+
+ public org.spongycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.spongycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.spongycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord());
+ }
+ else
+ {
+ return new org.spongycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord());
+ }
+ }
+
+ return q;
+ }
+
+ public org.spongycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECGOST3410PublicKey))
+ {
+ return false;
+ }
+
+ BCECGOST3410PublicKey other = (BCECGOST3410PublicKey)o;
+
+ return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+
+ public GOST3410PublicKeyAlgParameters getGostParams()
+ {
+ return gostParams;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
new file mode 100644
index 000000000..1552ff0a2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
@@ -0,0 +1,166 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+ }
+ }
+ else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false));
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec);
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false));
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec);
+ }
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPrivateKeySpec)
+ {
+ return new BCECGOST3410PrivateKey((ECPrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
+ {
+ return new BCECGOST3410PrivateKey((java.security.spec.ECPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+ {
+ return new BCECGOST3410PublicKey((java.security.spec.ECPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ return new BCECGOST3410PrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ return new BCECGOST3410PublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..5ceefa3df
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
@@ -0,0 +1,186 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.ECKeyPairGenerator;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECKeyGenerationParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ Object ecParams = null;
+ ECKeyPairGenerator engine = new ECKeyPairGenerator();
+
+ String algorithm = "ECGOST3410";
+ ECKeyGenerationParameters param;
+ int strength = 239;
+ SecureRandom random = null;
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("ECGOST3410");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+
+ if (ecParams != null)
+ {
+ try
+ {
+ initialize((ECGenParameterSpec)ecParams, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException("key size not configurable.");
+ }
+ }
+ else
+ {
+ throw new InvalidParameterException("unknown key size.");
+ }
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)params;
+ this.ecParams = params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof java.security.spec.ECParameterSpec)
+ {
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)params;
+ this.ecParams = params;
+
+ ECCurve curve = EC5Util.convertCurve(p.getCurve());
+ ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveGenParameterSpec)
+ {
+ String curveName;
+
+ if (params instanceof ECGenParameterSpec)
+ {
+ curveName = ((ECGenParameterSpec)params).getName();
+ }
+ else
+ {
+ curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+ }
+
+ ECDomainParameters ecP = ECGOST3410NamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+ }
+
+ this.ecParams = new ECNamedCurveSpec(
+ curveName,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+ ECCurve curve = EC5Util.convertCurve(p.getCurve());
+ ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() != null)
+ {
+ ECParameterSpec p = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ this.ecParams = params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() == null)
+ {
+ throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec: " + params.getClass().getName());
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException("EC Key Pair Generator not initialised");
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ if (ecParams instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)ecParams;
+
+ BCECGOST3410PublicKey pubKey = new BCECGOST3410PublicKey(algorithm, pub, p);
+ return new KeyPair(pubKey,
+ new BCECGOST3410PrivateKey(algorithm, priv, pubKey, p));
+ }
+ else if (ecParams == null)
+ {
+ return new KeyPair(new BCECGOST3410PublicKey(algorithm, pub),
+ new BCECGOST3410PrivateKey(algorithm, priv));
+ }
+ else
+ {
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+ BCECGOST3410PublicKey pubKey = new BCECGOST3410PublicKey(algorithm, pub, p);
+
+ return new KeyPair(pubKey, new BCECGOST3410PrivateKey(algorithm, priv, pubKey, p));
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
new file mode 100644
index 000000000..726dd9fc8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
@@ -0,0 +1,218 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.ECGOST3410Signer;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.GOST3410Key;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.util.GOST3410Util;
+
+public class SignatureSpi
+ extends java.security.SignatureSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+
+ public SignatureSpi()
+ {
+ this.digest = new GOST3411Digest();
+ this.signer = new ECGOST3410Signer();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else if (publicKey instanceof GOST3410Key)
+ {
+ param = GOST3410Util.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+ }
+
+ digest.reset();
+
+ if (appRandom != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, appRandom));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] sigBytes = new byte[64];
+ BigInteger[] sig = signer.generateSignature(hash);
+ byte[] r = sig[0].toByteArray();
+ byte[] s = sig[1].toByteArray();
+
+ if (s[0] != 0)
+ {
+ System.arraycopy(s, 0, sigBytes, 32 - s.length, s.length);
+ }
+ else
+ {
+ System.arraycopy(s, 1, sigBytes, 32 - (s.length - 1), s.length - 1);
+ }
+
+ if (r[0] != 0)
+ {
+ System.arraycopy(r, 0, sigBytes, 64 - r.length, r.length);
+ }
+ else
+ {
+ System.arraycopy(r, 1, sigBytes, 64 - (r.length - 1), r.length - 1);
+ }
+
+ return sigBytes;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ byte[] r = new byte[32];
+ byte[] s = new byte[32];
+
+ System.arraycopy(sigBytes, 0, s, 0, 32);
+
+ System.arraycopy(sigBytes, 32, r, 0, 32);
+
+ sig = new BigInteger[2];
+ sig[0] = new BigInteger(1, r);
+ sig[1] = new BigInteger(1, s);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParameterGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 000000000..332d6db14
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,76 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.crypto.generators.ElGamalParametersGenerator;
+import org.spongycastle.crypto.params.ElGamalParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class AlgorithmParameterGeneratorSpi
+ extends java.security.AlgorithmParameterGeneratorSpi
+{
+ protected SecureRandom random;
+ protected int strength = 1024;
+
+ private int l = 0;
+
+ protected void engineInit(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(genParamSpec instanceof DHGenParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
+ }
+ DHGenParameterSpec spec = (DHGenParameterSpec)genParamSpec;
+
+ this.strength = spec.getPrimeSize();
+ this.l = spec.getExponentSize();
+ this.random = random;
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
+
+ if (random != null)
+ {
+ pGen.init(strength, 20, random);
+ }
+ else
+ {
+ pGen.init(strength, 20, new SecureRandom());
+ }
+
+ ElGamalParameters p = pGen.generateParameters();
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("ElGamal", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new DHParameterSpec(p.getP(), p.getG(), l));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParametersSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParametersSpi.java
new file mode 100644
index 000000000..41b9a60fd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParametersSpi.java
@@ -0,0 +1,131 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.oiw.ElGamalParameter;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import org.spongycastle.jce.spec.ElGamalParameterSpec;
+
+public class AlgorithmParametersSpi
+ extends BaseAlgorithmParameters
+{
+ ElGamalParameterSpec currentSpec;
+
+ /**
+ * Return the X.509 ASN.1 structure ElGamalParameter.
+ * <p/>
+ * <pre>
+ * ElGamalParameter ::= SEQUENCE {
+ * prime INTEGER, -- p
+ * base INTEGER, -- g}
+ * </pre>
+ */
+ protected byte[] engineGetEncoded()
+ {
+ ElGamalParameter elP = new ElGamalParameter(currentSpec.getP(), currentSpec.getG());
+
+ try
+ {
+ return elP.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding ElGamalParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == ElGamalParameterSpec.class)
+ {
+ return currentSpec;
+ }
+ else if (paramSpec == DHParameterSpec.class)
+ {
+ return new DHParameterSpec(currentSpec.getP(), currentSpec.getG());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof ElGamalParameterSpec) && !(paramSpec instanceof DHParameterSpec))
+ {
+ throw new InvalidParameterSpecException("DHParameterSpec required to initialise a ElGamal algorithm parameters object");
+ }
+
+ if (paramSpec instanceof ElGamalParameterSpec)
+ {
+ this.currentSpec = (ElGamalParameterSpec)paramSpec;
+ }
+ else
+ {
+ DHParameterSpec s = (DHParameterSpec)paramSpec;
+
+ this.currentSpec = new ElGamalParameterSpec(s.getP(), s.getG());
+ }
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ ElGamalParameter elP = new ElGamalParameter((ASN1Sequence)ASN1Primitive.fromByteArray(params));
+
+ currentSpec = new ElGamalParameterSpec(elP.getP(), elP.getG());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid ElGamal Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid ElGamal Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "ElGamal Parameters";
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPrivateKey.java
new file mode 100644
index 000000000..4f02ba3fa
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPrivateKey.java
@@ -0,0 +1,199 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.oiw.ElGamalParameter;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.ElGamalPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.ElGamalPrivateKey;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.spec.ElGamalParameterSpec;
+import org.spongycastle.jce.spec.ElGamalPrivateKeySpec;
+
+public class BCElGamalPrivateKey
+ implements ElGamalPrivateKey, DHPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 4819350091141529678L;
+
+ private BigInteger x;
+
+ private transient ElGamalParameterSpec elSpec;
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCElGamalPrivateKey()
+ {
+ }
+
+ BCElGamalPrivateKey(
+ ElGamalPrivateKey key)
+ {
+ this.x = key.getX();
+ this.elSpec = key.getParameters();
+ }
+
+ BCElGamalPrivateKey(
+ DHPrivateKey key)
+ {
+ this.x = key.getX();
+ this.elSpec = new ElGamalParameterSpec(key.getParams().getP(), key.getParams().getG());
+ }
+
+ BCElGamalPrivateKey(
+ ElGamalPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.elSpec = new ElGamalParameterSpec(spec.getParams().getP(), spec.getParams().getG());
+ }
+
+ BCElGamalPrivateKey(
+ DHPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG());
+ }
+
+ BCElGamalPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ ElGamalParameter params = new ElGamalParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+ DERInteger derX = ASN1Integer.getInstance(info.parsePrivateKey());
+
+ this.x = derX.getValue();
+ this.elSpec = new ElGamalParameterSpec(params.getP(), params.getG());
+ }
+
+ BCElGamalPrivateKey(
+ ElGamalPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.elSpec = new ElGamalParameterSpec(params.getParameters().getP(), params.getParameters().getG());
+ }
+
+ public String getAlgorithm()
+ {
+ return "ElGamal";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(elSpec.getP(), elSpec.getG())), new DERInteger(getX()));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ElGamalParameterSpec getParameters()
+ {
+ return elSpec;
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return new DHParameterSpec(elSpec.getP(), elSpec.getG());
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DHPrivateKey))
+ {
+ return false;
+ }
+
+ DHPrivateKey other = (DHPrivateKey)o;
+
+ return this.getX().equals(other.getX())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getL() == other.getParams().getL();
+ }
+
+ public int hashCode()
+ {
+ return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.elSpec = new ElGamalParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject());
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(elSpec.getP());
+ out.writeObject(elSpec.getG());
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPublicKey.java
new file mode 100644
index 000000000..20d668cf4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPublicKey.java
@@ -0,0 +1,173 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.oiw.ElGamalParameter;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.params.ElGamalPublicKeyParameters;
+import org.spongycastle.jce.interfaces.ElGamalPublicKey;
+import org.spongycastle.jce.spec.ElGamalParameterSpec;
+import org.spongycastle.jce.spec.ElGamalPublicKeySpec;
+
+public class BCElGamalPublicKey
+ implements ElGamalPublicKey, DHPublicKey
+{
+ static final long serialVersionUID = 8712728417091216948L;
+
+ private BigInteger y;
+ private transient ElGamalParameterSpec elSpec;
+
+ BCElGamalPublicKey(
+ ElGamalPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.elSpec = new ElGamalParameterSpec(spec.getParams().getP(), spec.getParams().getG());
+ }
+
+ BCElGamalPublicKey(
+ DHPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG());
+ }
+
+ BCElGamalPublicKey(
+ ElGamalPublicKey key)
+ {
+ this.y = key.getY();
+ this.elSpec = key.getParameters();
+ }
+
+ BCElGamalPublicKey(
+ DHPublicKey key)
+ {
+ this.y = key.getY();
+ this.elSpec = new ElGamalParameterSpec(key.getParams().getP(), key.getParams().getG());
+ }
+
+ BCElGamalPublicKey(
+ ElGamalPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.elSpec = new ElGamalParameterSpec(params.getParameters().getP(), params.getParameters().getG());
+ }
+
+ BCElGamalPublicKey(
+ BigInteger y,
+ ElGamalParameterSpec elSpec)
+ {
+ this.y = y;
+ this.elSpec = elSpec;
+ }
+
+ BCElGamalPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ ElGamalParameter params = new ElGamalParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+ DERInteger derY = null;
+
+ try
+ {
+ derY = (DERInteger)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DSA public key");
+ }
+
+ this.y = derY.getValue();
+ this.elSpec = new ElGamalParameterSpec(params.getP(), params.getG());
+ }
+
+ public String getAlgorithm()
+ {
+ return "ElGamal";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(elSpec.getP(), elSpec.getG())), new DERInteger(y));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ElGamalParameterSpec getParameters()
+ {
+ return elSpec;
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return new DHParameterSpec(elSpec.getP(), elSpec.getG());
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public int hashCode()
+ {
+ return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DHPublicKey))
+ {
+ return false;
+ }
+
+ DHPublicKey other = (DHPublicKey)o;
+
+ return this.getY().equals(other.getY())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getL() == other.getParams().getL();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.elSpec = new ElGamalParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(elSpec.getP());
+ out.writeObject(elSpec.getG());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
new file mode 100644
index 000000000..123b88b55
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
@@ -0,0 +1,340 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.interfaces.DHKey;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.BufferedAsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.encodings.ISO9796d1Encoding;
+import org.spongycastle.crypto.encodings.OAEPEncoding;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.ElGamalEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.spongycastle.jcajce.provider.util.DigestFactory;
+import org.spongycastle.jce.interfaces.ElGamalKey;
+import org.spongycastle.jce.interfaces.ElGamalPrivateKey;
+import org.spongycastle.jce.interfaces.ElGamalPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class CipherSpi
+ extends BaseCipherSpi
+{
+ private BufferedAsymmetricBlockCipher cipher;
+ private AlgorithmParameterSpec paramSpec;
+ private AlgorithmParameters engineParams;
+
+ public CipherSpi(
+ AsymmetricBlockCipher engine)
+ {
+ cipher = new BufferedAsymmetricBlockCipher(engine);
+ }
+
+ private void initFromSpec(
+ OAEPParameterSpec pSpec)
+ throws NoSuchPaddingException
+ {
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)pSpec.getMGFParameters();
+ Digest digest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (digest == null)
+ {
+ throw new NoSuchPaddingException("no match on OAEP constructor for digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ cipher = new BufferedAsymmetricBlockCipher(new OAEPEncoding(new ElGamalEngine(), digest, ((PSource.PSpecified)pSpec.getPSource()).getValue()));
+ paramSpec = pSpec;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return cipher.getInputBlockSize();
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (key instanceof ElGamalKey)
+ {
+ ElGamalKey k = (ElGamalKey)key;
+
+ return k.getParameters().getP().bitLength();
+ }
+ else if (key instanceof DHKey)
+ {
+ DHKey k = (DHKey)key;
+
+ return k.getParams().getP().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an ElGamal key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return cipher.getOutputBlockSize();
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ String md = Strings.toUpperCase(mode);
+
+ if (md.equals("NONE") || md.equals("ECB"))
+ {
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String pad = Strings.toUpperCase(padding);
+
+ if (pad.equals("NOPADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new ElGamalEngine());
+ }
+ else if (pad.equals("PKCS1PADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new PKCS1Encoding(new ElGamalEngine()));
+ }
+ else if (pad.equals("ISO9796-1PADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new ISO9796d1Encoding(new ElGamalEngine()));
+ }
+ else if (pad.equals("OAEPPADDING"))
+ {
+ initFromSpec(OAEPParameterSpec.DEFAULT);
+ }
+ else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("MD5", "MGF1", new MGF1ParameterSpec("MD5"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING"))
+ {
+ initFromSpec(OAEPParameterSpec.DEFAULT);
+ }
+ else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
+ }
+ else
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with ElGamal.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (params == null)
+ {
+ if (key instanceof ElGamalPublicKey)
+ {
+ param = ElGamalUtil.generatePublicKeyParameter((PublicKey)key);
+ }
+ else if (key instanceof ElGamalPrivateKey)
+ {
+ param = ElGamalUtil.generatePrivateKeyParameter((PrivateKey)key);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown key type passed to ElGamal");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown parameter type.");
+ }
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ switch (opmode)
+ {
+ case javax.crypto.Cipher.ENCRYPT_MODE:
+ case javax.crypto.Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case javax.crypto.Cipher.DECRYPT_MODE:
+ case javax.crypto.Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed to ElGamal");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameters in ElGamal");
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ try
+ {
+ return cipher.doFinal();
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ byte[] out;
+
+ cipher.processBytes(input, inputOffset, inputLen);
+
+ try
+ {
+ out = cipher.doFinal();
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+
+ /**
+ * classes that inherit from us.
+ */
+ static public class NoPadding
+ extends CipherSpi
+ {
+ public NoPadding()
+ {
+ super(new ElGamalEngine());
+ }
+ }
+
+ static public class PKCS1v1_5Padding
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding()
+ {
+ super(new PKCS1Encoding(new ElGamalEngine()));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/ElGamalUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/ElGamalUtil.java
new file mode 100644
index 000000000..65c7c4124
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/ElGamalUtil.java
@@ -0,0 +1,66 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ElGamalParameters;
+import org.spongycastle.crypto.params.ElGamalPrivateKeyParameters;
+import org.spongycastle.crypto.params.ElGamalPublicKeyParameters;
+import org.spongycastle.jce.interfaces.ElGamalPrivateKey;
+import org.spongycastle.jce.interfaces.ElGamalPublicKey;
+
+/**
+ * utility class for converting jce/jca ElGamal objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class ElGamalUtil
+{
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ElGamalPublicKey)
+ {
+ ElGamalPublicKey k = (ElGamalPublicKey)key;
+
+ return new ElGamalPublicKeyParameters(k.getY(),
+ new ElGamalParameters(k.getParameters().getP(), k.getParameters().getG()));
+ }
+ else if (key instanceof DHPublicKey)
+ {
+ DHPublicKey k = (DHPublicKey)key;
+
+ return new ElGamalPublicKeyParameters(k.getY(),
+ new ElGamalParameters(k.getParams().getP(), k.getParams().getG()));
+ }
+
+ throw new InvalidKeyException("can't identify public key for El Gamal.");
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ElGamalPrivateKey)
+ {
+ ElGamalPrivateKey k = (ElGamalPrivateKey)key;
+
+ return new ElGamalPrivateKeyParameters(k.getX(),
+ new ElGamalParameters(k.getParameters().getP(), k.getParameters().getG()));
+ }
+ else if (key instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)key;
+
+ return new ElGamalPrivateKeyParameters(k.getX(),
+ new ElGamalParameters(k.getParams().getP(), k.getParams().getG()));
+ }
+
+ throw new InvalidKeyException("can't identify private key for El Gamal.");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/KeyFactorySpi.java
new file mode 100644
index 000000000..03c685e33
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/KeyFactorySpi.java
@@ -0,0 +1,156 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jce.interfaces.ElGamalPrivateKey;
+import org.spongycastle.jce.interfaces.ElGamalPublicKey;
+import org.spongycastle.jce.spec.ElGamalPrivateKeySpec;
+import org.spongycastle.jce.spec.ElGamalPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ElGamalPrivateKeySpec)
+ {
+ return new BCElGamalPrivateKey((ElGamalPrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof DHPrivateKeySpec)
+ {
+ return new BCElGamalPrivateKey((DHPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ElGamalPublicKeySpec)
+ {
+ return new BCElGamalPublicKey((ElGamalPublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof DHPublicKeySpec)
+ {
+ return new BCElGamalPublicKey((DHPublicKeySpec)keySpec);
+ }
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(DHPrivateKeySpec.class) && key instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)key;
+
+ return new DHPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getG());
+ }
+ else if (spec.isAssignableFrom(DHPublicKeySpec.class) && key instanceof DHPublicKey)
+ {
+ DHPublicKey k = (DHPublicKey)key;
+
+ return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPublicKey)
+ {
+ return new BCElGamalPublicKey((DHPublicKey)key);
+ }
+ else if (key instanceof DHPrivateKey)
+ {
+ return new BCElGamalPrivateKey((DHPrivateKey)key);
+ }
+ else if (key instanceof ElGamalPublicKey)
+ {
+ return new BCElGamalPublicKey((ElGamalPublicKey)key);
+ }
+ else if (key instanceof ElGamalPrivateKey)
+ {
+ return new BCElGamalPrivateKey((ElGamalPrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo info)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = info.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ return new BCElGamalPrivateKey(info);
+ }
+ else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ return new BCElGamalPrivateKey(info);
+ }
+ else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
+ {
+ return new BCElGamalPrivateKey(info);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo info)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = info.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ return new BCElGamalPublicKey(info);
+ }
+ else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ return new BCElGamalPublicKey(info);
+ }
+ else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
+ {
+ return new BCElGamalPublicKey(info);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..9c92b575c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/elgamal/KeyPairGeneratorSpi.java
@@ -0,0 +1,100 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.ElGamalKeyPairGenerator;
+import org.spongycastle.crypto.generators.ElGamalParametersGenerator;
+import org.spongycastle.crypto.params.ElGamalKeyGenerationParameters;
+import org.spongycastle.crypto.params.ElGamalParameters;
+import org.spongycastle.crypto.params.ElGamalPrivateKeyParameters;
+import org.spongycastle.crypto.params.ElGamalPublicKeyParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ElGamalParameterSpec;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ ElGamalKeyGenerationParameters param;
+ ElGamalKeyPairGenerator engine = new ElGamalKeyPairGenerator();
+ int strength = 1024;
+ int certainty = 20;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("ElGamal");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof ElGamalParameterSpec) && !(params instanceof DHParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec or an ElGamalParameterSpec");
+ }
+
+ if (params instanceof ElGamalParameterSpec)
+ {
+ ElGamalParameterSpec elParams = (ElGamalParameterSpec)params;
+
+ param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(elParams.getP(), elParams.getG()));
+ }
+ else
+ {
+ DHParameterSpec dhParams = (DHParameterSpec)params;
+
+ param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(dhParams.getP(), dhParams.getG(), dhParams.getL()));
+ }
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ DHParameterSpec dhParams = BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(strength);
+
+ if (dhParams != null)
+ {
+ param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(dhParams.getP(), dhParams.getG(), dhParams.getL()));
+ }
+ else
+ {
+ ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
+
+ pGen.init(strength, certainty, random);
+ param = new ElGamalKeyGenerationParameters(random, pGen.generateParameters());
+ }
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ElGamalPublicKeyParameters pub = (ElGamalPublicKeyParameters)pair.getPublic();
+ ElGamalPrivateKeyParameters priv = (ElGamalPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCElGamalPublicKey(pub),
+ new BCElGamalPrivateKey(priv));
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/AlgorithmParameterGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 000000000..0cf5908ac
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,65 @@
+package org.spongycastle.jcajce.provider.asymmetric.gost;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.generators.GOST3410ParametersGenerator;
+import org.spongycastle.crypto.params.GOST3410Parameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+
+public abstract class AlgorithmParameterGeneratorSpi
+ extends java.security.AlgorithmParameterGeneratorSpi
+{
+ protected SecureRandom random;
+ protected int strength = 1024;
+
+ protected void engineInit(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
+
+ if (random != null)
+ {
+ pGen.init(strength, 2, random);
+ }
+ else
+ {
+ pGen.init(strength, 2, new SecureRandom());
+ }
+
+ GOST3410Parameters p = pGen.generateParameters();
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("GOST3410", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/AlgorithmParametersSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/AlgorithmParametersSpi.java
new file mode 100644
index 000000000..c046d0080
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/AlgorithmParametersSpi.java
@@ -0,0 +1,138 @@
+package org.spongycastle.jcajce.provider.asymmetric.gost;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+
+public class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ GOST3410ParameterSpec currentSpec;
+
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+
+ /**
+ * Return the X.509 ASN.1 structure GOST3410Parameter.
+ * <p/>
+ * <pre>
+ * GOST3410Parameter ::= SEQUENCE {
+ * prime INTEGER, -- p
+ * subprime INTEGER, -- q
+ * base INTEGER, -- a}
+ * </pre>
+ */
+ protected byte[] engineGetEncoded()
+ {
+ GOST3410PublicKeyAlgParameters gost3410P = new GOST3410PublicKeyAlgParameters(new ASN1ObjectIdentifier(currentSpec.getPublicKeyParamSetOID()), new ASN1ObjectIdentifier(currentSpec.getDigestParamSetOID()), new ASN1ObjectIdentifier(currentSpec.getEncryptionParamSetOID()));
+
+ try
+ {
+ return gost3410P.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding GOST3410Parameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == GOST3410PublicKeyParameterSetSpec.class)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to GOST3410 parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof GOST3410ParameterSpec))
+ {
+ throw new InvalidParameterSpecException("GOST3410ParameterSpec required to initialise a GOST3410 algorithm parameters object");
+ }
+
+ this.currentSpec = (GOST3410ParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(params);
+
+ this.currentSpec = GOST3410ParameterSpec.fromPublicKeyAlg(
+ new GOST3410PublicKeyAlgParameters(seq));
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid GOST3410 Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid GOST3410 Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "GOST3410 Parameters";
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java
new file mode 100644
index 000000000..13340f1ef
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java
@@ -0,0 +1,253 @@
+package org.spongycastle.jcajce.provider.asymmetric.gost;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.GOST3410PrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.GOST3410Params;
+import org.spongycastle.jce.interfaces.GOST3410PrivateKey;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.jce.spec.GOST3410PrivateKeySpec;
+import org.spongycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+
+public class BCGOST3410PrivateKey
+ implements GOST3410PrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 8581661527592305464L;
+
+ private BigInteger x;
+
+ private transient GOST3410Params gost3410Spec;
+ private transient PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCGOST3410PrivateKey()
+ {
+ }
+
+ BCGOST3410PrivateKey(
+ GOST3410PrivateKey key)
+ {
+ this.x = key.getX();
+ this.gost3410Spec = key.getParameters();
+ }
+
+ BCGOST3410PrivateKey(
+ GOST3410PrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.gost3410Spec = new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(spec.getP(), spec.getQ(), spec.getA()));
+ }
+
+ BCGOST3410PrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ GOST3410PublicKeyAlgParameters params = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+ ASN1OctetString derX = ASN1OctetString.getInstance(info.parsePrivateKey());
+ byte[] keyEnc = derX.getOctets();
+ byte[] keyBytes = new byte[keyEnc.length];
+
+ for (int i = 0; i != keyEnc.length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.length - 1 - i]; // was little endian
+ }
+
+ this.x = new BigInteger(1, keyBytes);
+ this.gost3410Spec = GOST3410ParameterSpec.fromPublicKeyAlg(params);
+ }
+
+ BCGOST3410PrivateKey(
+ GOST3410PrivateKeyParameters params,
+ GOST3410ParameterSpec spec)
+ {
+ this.x = params.getX();
+ this.gost3410Spec = spec;
+
+ if (spec == null)
+ {
+ throw new IllegalArgumentException("spec is null");
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return "GOST3410";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ PrivateKeyInfo info;
+ byte[] keyEnc = this.getX().toByteArray();
+ byte[] keyBytes;
+
+ if (keyEnc[0] == 0)
+ {
+ keyBytes = new byte[keyEnc.length - 1];
+ }
+ else
+ {
+ keyBytes = new byte[keyEnc.length];
+ }
+
+ for (int i = 0; i != keyBytes.length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.length - 1 - i]; // must be little endian
+ }
+
+ try
+ {
+ if (gost3410Spec instanceof GOST3410ParameterSpec)
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_94, new GOST3410PublicKeyAlgParameters(new ASN1ObjectIdentifier(gost3410Spec.getPublicKeyParamSetOID()), new ASN1ObjectIdentifier(gost3410Spec.getDigestParamSetOID()))), new DEROctetString(keyBytes));
+ }
+ else
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_94), new DEROctetString(keyBytes));
+ }
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public GOST3410Params getParameters()
+ {
+ return gost3410Spec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof GOST3410PrivateKey))
+ {
+ return false;
+ }
+
+ GOST3410PrivateKey other = (GOST3410PrivateKey)o;
+
+ return this.getX().equals(other.getX())
+ && this.getParameters().getPublicKeyParameters().equals(other.getParameters().getPublicKeyParameters())
+ && this.getParameters().getDigestParamSetOID().equals(other.getParameters().getDigestParamSetOID())
+ && compareObj(this.getParameters().getEncryptionParamSetOID(), other.getParameters().getEncryptionParamSetOID());
+ }
+
+ private boolean compareObj(Object o1, Object o2)
+ {
+ if (o1 == o2)
+ {
+ return true;
+ }
+
+ if (o1 == null)
+ {
+ return false;
+ }
+
+ return o1.equals(o2);
+ }
+
+ public int hashCode()
+ {
+ return this.getX().hashCode() ^ gost3410Spec.hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ String publicKeyParamSetOID = (String)in.readObject();
+ if (publicKeyParamSetOID != null)
+ {
+ this.gost3410Spec = new GOST3410ParameterSpec(publicKeyParamSetOID, (String)in.readObject(), (String)in.readObject());
+ }
+ else
+ {
+ this.gost3410Spec = new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject()));
+ in.readObject();
+ in.readObject();
+ }
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ if (gost3410Spec.getPublicKeyParamSetOID() != null)
+ {
+ out.writeObject(gost3410Spec.getPublicKeyParamSetOID());
+ out.writeObject(gost3410Spec.getDigestParamSetOID());
+ out.writeObject(gost3410Spec.getEncryptionParamSetOID());
+ }
+ else
+ {
+ out.writeObject(null);
+ out.writeObject(gost3410Spec.getPublicKeyParameters().getP());
+ out.writeObject(gost3410Spec.getPublicKeyParameters().getQ());
+ out.writeObject(gost3410Spec.getPublicKeyParameters().getA());
+ out.writeObject(gost3410Spec.getDigestParamSetOID());
+ out.writeObject(gost3410Spec.getEncryptionParamSetOID());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/BCGOST3410PublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/BCGOST3410PublicKey.java
new file mode 100644
index 000000000..658715c94
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/BCGOST3410PublicKey.java
@@ -0,0 +1,224 @@
+package org.spongycastle.jcajce.provider.asymmetric.gost;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.params.GOST3410PublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jce.interfaces.GOST3410Params;
+import org.spongycastle.jce.interfaces.GOST3410PublicKey;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+import org.spongycastle.jce.spec.GOST3410PublicKeySpec;
+
+public class BCGOST3410PublicKey
+ implements GOST3410PublicKey
+{
+ static final long serialVersionUID = -6251023343619275990L;
+
+ private BigInteger y;
+ private transient GOST3410Params gost3410Spec;
+
+ BCGOST3410PublicKey(
+ GOST3410PublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.gost3410Spec = new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(spec.getP(), spec.getQ(), spec.getA()));
+ }
+
+ BCGOST3410PublicKey(
+ GOST3410PublicKey key)
+ {
+ this.y = key.getY();
+ this.gost3410Spec = key.getParameters();
+ }
+
+ BCGOST3410PublicKey(
+ GOST3410PublicKeyParameters params,
+ GOST3410ParameterSpec spec)
+ {
+ this.y = params.getY();
+ this.gost3410Spec = spec;
+ }
+
+ BCGOST3410PublicKey(
+ BigInteger y,
+ GOST3410ParameterSpec gost3410Spec)
+ {
+ this.y = y;
+ this.gost3410Spec = gost3410Spec;
+ }
+
+ BCGOST3410PublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ GOST3410PublicKeyAlgParameters params = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+ DEROctetString derY;
+
+ try
+ {
+ derY = (DEROctetString)info.parsePublicKey();
+
+ byte[] keyEnc = derY.getOctets();
+ byte[] keyBytes = new byte[keyEnc.length];
+
+ for (int i = 0; i != keyEnc.length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.length - 1 - i]; // was little endian
+ }
+
+ this.y = new BigInteger(1, keyBytes);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in GOST3410 public key");
+ }
+
+ this.gost3410Spec = GOST3410ParameterSpec.fromPublicKeyAlg(params);
+ }
+
+ public String getAlgorithm()
+ {
+ return "GOST3410";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ SubjectPublicKeyInfo info;
+ byte[] keyEnc = this.getY().toByteArray();
+ byte[] keyBytes;
+
+ if (keyEnc[0] == 0)
+ {
+ keyBytes = new byte[keyEnc.length - 1];
+ }
+ else
+ {
+ keyBytes = new byte[keyEnc.length];
+ }
+
+ for (int i = 0; i != keyBytes.length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.length - 1 - i]; // must be little endian
+ }
+
+ try
+ {
+ if (gost3410Spec instanceof GOST3410ParameterSpec)
+ {
+ if (gost3410Spec.getEncryptionParamSetOID() != null)
+ {
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_94, new GOST3410PublicKeyAlgParameters(new ASN1ObjectIdentifier(gost3410Spec.getPublicKeyParamSetOID()), new ASN1ObjectIdentifier(gost3410Spec.getDigestParamSetOID()), new ASN1ObjectIdentifier(gost3410Spec.getEncryptionParamSetOID()))), new DEROctetString(keyBytes));
+ }
+ else
+ {
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_94, new GOST3410PublicKeyAlgParameters(new ASN1ObjectIdentifier(gost3410Spec.getPublicKeyParamSetOID()), new ASN1ObjectIdentifier(gost3410Spec.getDigestParamSetOID()))), new DEROctetString(keyBytes));
+ }
+ }
+ else
+ {
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_94), new DEROctetString(keyBytes));
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public GOST3410Params getParameters()
+ {
+ return gost3410Spec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("GOST3410 Public Key").append(nl);
+ buf.append(" y: ").append(this.getY().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o instanceof BCGOST3410PublicKey)
+ {
+ BCGOST3410PublicKey other = (BCGOST3410PublicKey)o;
+
+ return this.y.equals(other.y) && this.gost3410Spec.equals(other.gost3410Spec);
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return y.hashCode() ^ gost3410Spec.hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ String publicKeyParamSetOID = (String)in.readObject();
+ if (publicKeyParamSetOID != null)
+ {
+ this.gost3410Spec = new GOST3410ParameterSpec(publicKeyParamSetOID, (String)in.readObject(), (String)in.readObject());
+ }
+ else
+ {
+ this.gost3410Spec = new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject()));
+ in.readObject();
+ in.readObject();
+ }
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ if (gost3410Spec.getPublicKeyParamSetOID() != null)
+ {
+ out.writeObject(gost3410Spec.getPublicKeyParamSetOID());
+ out.writeObject(gost3410Spec.getDigestParamSetOID());
+ out.writeObject(gost3410Spec.getEncryptionParamSetOID());
+ }
+ else
+ {
+ out.writeObject(null);
+ out.writeObject(gost3410Spec.getPublicKeyParameters().getP());
+ out.writeObject(gost3410Spec.getPublicKeyParameters().getQ());
+ out.writeObject(gost3410Spec.getPublicKeyParameters().getA());
+ out.writeObject(gost3410Spec.getDigestParamSetOID());
+ out.writeObject(gost3410Spec.getEncryptionParamSetOID());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/KeyFactorySpi.java
new file mode 100644
index 000000000..acf1f4808
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/KeyFactorySpi.java
@@ -0,0 +1,121 @@
+package org.spongycastle.jcajce.provider.asymmetric.gost;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jce.interfaces.GOST3410PrivateKey;
+import org.spongycastle.jce.interfaces.GOST3410PublicKey;
+import org.spongycastle.jce.spec.GOST3410PrivateKeySpec;
+import org.spongycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+import org.spongycastle.jce.spec.GOST3410PublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(GOST3410PublicKeySpec.class) && key instanceof GOST3410PublicKey)
+ {
+ GOST3410PublicKey k = (GOST3410PublicKey)key;
+ GOST3410PublicKeyParameterSetSpec parameters = k.getParameters().getPublicKeyParameters();
+
+ return new GOST3410PublicKeySpec(k.getY(), parameters.getP(), parameters.getQ(), parameters.getA());
+ }
+ else if (spec.isAssignableFrom(GOST3410PrivateKeySpec.class) && key instanceof GOST3410PrivateKey)
+ {
+ GOST3410PrivateKey k = (GOST3410PrivateKey)key;
+ GOST3410PublicKeyParameterSetSpec parameters = k.getParameters().getPublicKeyParameters();
+
+ return new GOST3410PrivateKeySpec(k.getX(), parameters.getP(), parameters.getQ(), parameters.getA());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof GOST3410PublicKey)
+ {
+ return new BCGOST3410PublicKey((GOST3410PublicKey)key);
+ }
+ else if (key instanceof GOST3410PrivateKey)
+ {
+ return new BCGOST3410PrivateKey((GOST3410PrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof GOST3410PrivateKeySpec)
+ {
+ return new BCGOST3410PrivateKey((GOST3410PrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof GOST3410PublicKeySpec)
+ {
+ return new BCGOST3410PublicKey((GOST3410PublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
+ {
+ return new BCGOST3410PrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
+ {
+ return new BCGOST3410PublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..67ac1b91a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/KeyPairGeneratorSpi.java
@@ -0,0 +1,81 @@
+package org.spongycastle.jcajce.provider.asymmetric.gost;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.GOST3410KeyPairGenerator;
+import org.spongycastle.crypto.params.GOST3410KeyGenerationParameters;
+import org.spongycastle.crypto.params.GOST3410Parameters;
+import org.spongycastle.crypto.params.GOST3410PrivateKeyParameters;
+import org.spongycastle.crypto.params.GOST3410PublicKeyParameters;
+import org.spongycastle.jce.spec.GOST3410ParameterSpec;
+import org.spongycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ GOST3410KeyGenerationParameters param;
+ GOST3410KeyPairGenerator engine = new GOST3410KeyPairGenerator();
+ GOST3410ParameterSpec gost3410Params;
+ int strength = 1024;
+ SecureRandom random = null;
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("GOST3410");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ private void init(
+ GOST3410ParameterSpec gParams,
+ SecureRandom random)
+ {
+ GOST3410PublicKeyParameterSetSpec spec = gParams.getPublicKeyParameters();
+
+ param = new GOST3410KeyGenerationParameters(random, new GOST3410Parameters(spec.getP(), spec.getQ(), spec.getA()));
+
+ engine.init(param);
+
+ initialised = true;
+ gost3410Params = gParams;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof GOST3410ParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a GOST3410ParameterSpec");
+ }
+
+ init((GOST3410ParameterSpec)params, random);
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ init(new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId()), new SecureRandom());
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ GOST3410PublicKeyParameters pub = (GOST3410PublicKeyParameters)pair.getPublic();
+ GOST3410PrivateKeyParameters priv = (GOST3410PrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCGOST3410PublicKey(pub, gost3410Params), new BCGOST3410PrivateKey(priv, gost3410Params));
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java
new file mode 100644
index 000000000..199af6dc4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java
@@ -0,0 +1,229 @@
+package org.spongycastle.jcajce.provider.asymmetric.gost;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.GOST3410Signer;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.GOST3410Key;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.util.GOST3410Util;
+
+public class SignatureSpi
+ extends java.security.SignatureSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+ private SecureRandom random;
+
+ public SignatureSpi()
+ {
+ this.digest = new GOST3411Digest();
+ this.signer = new GOST3410Signer();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else if (publicKey instanceof GOST3410Key)
+ {
+ param = GOST3410Util.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+ }
+
+ digest.reset();
+
+ if (random != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, random));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] sigBytes = new byte[64];
+ BigInteger[] sig = signer.generateSignature(hash);
+ byte[] r = sig[0].toByteArray();
+ byte[] s = sig[1].toByteArray();
+
+ if (s[0] != 0)
+ {
+ System.arraycopy(s, 0, sigBytes, 32 - s.length, s.length);
+ }
+ else
+ {
+ System.arraycopy(s, 1, sigBytes, 32 - (s.length - 1), s.length - 1);
+ }
+
+ if (r[0] != 0)
+ {
+ System.arraycopy(r, 0, sigBytes, 64 - r.length, r.length);
+ }
+ else
+ {
+ System.arraycopy(r, 1, sigBytes, 64 - (r.length - 1), r.length - 1);
+ }
+
+ return sigBytes;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ byte[] r = new byte[32];
+ byte[] s = new byte[32];
+
+ System.arraycopy(sigBytes, 0, s, 0, 32);
+
+ System.arraycopy(sigBytes, 32, r, 0, 32);
+
+ sig = new BigInteger[2];
+ sig[0] = new BigInteger(1, r);
+ sig[1] = new BigInteger(1, s);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java
new file mode 100644
index 000000000..1fd8b90d5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java
@@ -0,0 +1,138 @@
+package org.spongycastle.jcajce.provider.asymmetric.ies;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.jce.spec.IESParameterSpec;
+
+public class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ IESParameterSpec currentSpec;
+
+ /**
+ * in the absence of a standard way of doing it this will do for
+ * now...
+ */
+ protected byte[] engineGetEncoded()
+ {
+ try
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DEROctetString(currentSpec.getDerivationV()));
+ v.add(new DEROctetString(currentSpec.getEncodingV()));
+ v.add(new DERInteger(currentSpec.getMacKeySize()));
+
+ return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding IESParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IESParameterSpec.class)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof IESParameterSpec))
+ {
+ throw new InvalidParameterSpecException("IESParameterSpec required to initialise a IES algorithm parameters object");
+ }
+
+ this.currentSpec = (IESParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(params);
+
+ this.currentSpec = new IESParameterSpec(
+ ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+ ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+ ((DERInteger)s.getObjectAt(0)).getValue().intValue());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid IES Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid IES Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "IES Parameters";
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java
new file mode 100644
index 000000000..9337df043
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java
@@ -0,0 +1,363 @@
+package org.spongycastle.jcajce.provider.asymmetric.ies;
+
+import java.io.ByteArrayOutputStream;
+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 javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.interfaces.DHPrivateKey;
+
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.agreement.DHBasicAgreement;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.engines.IESEngine;
+import org.spongycastle.crypto.generators.KDF2BytesGenerator;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.crypto.params.IESParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.util.DHUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.IESKey;
+import org.spongycastle.jce.spec.IESParameterSpec;
+
+public class CipherSpi
+ extends javax.crypto.CipherSpi
+{
+ private IESEngine cipher;
+ private int state = -1;
+ private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ private AlgorithmParameters engineParam = null;
+ private IESParameterSpec engineParams = null;
+
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ IESParameterSpec.class
+ };
+
+ public CipherSpi(
+ IESEngine engine)
+ {
+ cipher = engine;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return 0;
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (!(key instanceof IESKey))
+ {
+ throw new IllegalArgumentException("must be passed IE key");
+ }
+
+ IESKey ieKey = (IESKey)key;
+
+ if (ieKey.getPrivate() instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)ieKey.getPrivate();
+
+ return k.getX().bitLength();
+ }
+ else if (ieKey.getPrivate() instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)ieKey.getPrivate();
+
+ return k.getD().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an IE key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+ {
+ return buffer.size() + inputLen + 20; /* SHA1 MAC size */
+ }
+ else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
+ {
+ return buffer.size() + inputLen - 20;
+ }
+ else
+ {
+ throw new IllegalStateException("cipher not initialised");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParam == null)
+ {
+ if (engineParams != null)
+ {
+ String name = "IES";
+
+ try
+ {
+ engineParam = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
+ engineParam.init(engineParams);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParam;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ {
+ throw new IllegalArgumentException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ if (!(key instanceof IESKey))
+ {
+ throw new InvalidKeyException("must be passed IES key");
+ }
+
+ if (params == null && (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE))
+ {
+ //
+ // if nothing is specified we set up for a 128 bit mac, with
+ // 128 bit derivation vectors.
+ //
+ byte[] d = new byte[16];
+ byte[] e = new byte[16];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(d);
+ random.nextBytes(e);
+
+ params = new IESParameterSpec(d, e, 128);
+ }
+ else if (!(params instanceof IESParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("must be passed IES parameters");
+ }
+
+ IESKey ieKey = (IESKey)key;
+
+ CipherParameters pubKey;
+ CipherParameters privKey;
+
+ if (ieKey.getPublic() instanceof ECPublicKey)
+ {
+ pubKey = ECUtil.generatePublicKeyParameter(ieKey.getPublic());
+ privKey = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate());
+ }
+ else
+ {
+ pubKey = DHUtil.generatePublicKeyParameter(ieKey.getPublic());
+ privKey = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate());
+ }
+
+ this.engineParams = (IESParameterSpec)params;
+
+ IESParameters p = new IESParameters(engineParams.getDerivationV(), engineParams.getEncodingV(), engineParams.getMacKeySize());
+
+ this.state = opmode;
+
+ buffer.reset();
+
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, privKey, pubKey, p);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, privKey, pubKey, p);
+ break;
+ default:
+ System.out.println("eeek!");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ for (int i = 0; i != availableSpecs.length; i++)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(availableSpecs[i]);
+ break;
+ }
+ catch (Exception e)
+ {
+ continue;
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineParam = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ return;
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // fall through...
+ }
+ }
+
+ throw new IllegalArgumentException("can't handle null parameter spec in IES");
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (inputLen != 0)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ }
+
+ try
+ {
+ byte[] buf = buffer.toByteArray();
+
+ buffer.reset();
+
+ return cipher.processBlock(buf, 0, buf.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (inputLen != 0)
+ {
+ buffer.write(input, inputOffset, inputLen);
+ }
+
+ try
+ {
+ byte[] buf = buffer.toByteArray();
+
+ buffer.reset();
+
+ buf = cipher.processBlock(buf, 0, buf.length);
+
+ System.arraycopy(buf, 0, output, outputOffset, buf.length);
+
+ return buf.length;
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ static public class IES
+ extends CipherSpi
+ {
+ public IES()
+ {
+ super(new IESEngine(
+ new DHBasicAgreement(),
+ new KDF2BytesGenerator(new SHA1Digest()),
+ new HMac(new SHA1Digest())));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 000000000..6402bd28a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,265 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.provider.util.DigestFactory;
+
+public abstract class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class OAEP
+ extends AlgorithmParametersSpi
+ {
+ OAEPParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
+ */
+ protected byte[] engineGetEncoded()
+ {
+ AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+ DigestFactory.getOID(currentSpec.getDigestAlgorithm()),
+ DERNull.INSTANCE);
+ MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
+ AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_mgf1,
+ new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+ PSource.PSpecified pSource = (PSource.PSpecified)currentSpec.getPSource();
+ AlgorithmIdentifier pSourceAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
+ RSAESOAEPparams oaepP = new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, pSourceAlgorithm);
+
+ try
+ {
+ return oaepP.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding OAEPParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == OAEPParameterSpec.class && currentSpec != null)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof OAEPParameterSpec))
+ {
+ throw new InvalidParameterSpecException("OAEPParameterSpec required to initialise an OAEP algorithm parameters object");
+ }
+
+ this.currentSpec = (OAEPParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+
+ currentSpec = new OAEPParameterSpec(
+ oaepP.getHashAlgorithm().getAlgorithm().getId(),
+ oaepP.getMaskGenAlgorithm().getAlgorithm().getId(),
+ new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+ new PSource.PSpecified(ASN1OctetString.getInstance(oaepP.getPSourceAlgorithm().getParameters()).getOctets()));
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "OAEP Parameters";
+ }
+ }
+
+ public static class PSS
+ extends AlgorithmParametersSpi
+ {
+ PSSParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+ */
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ PSSParameterSpec pssSpec = currentSpec;
+ AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+ DigestFactory.getOID(pssSpec.getDigestAlgorithm()),
+ DERNull.INSTANCE);
+ MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
+ AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_mgf1,
+ new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+ RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new ASN1Integer(pssSpec.getSaltLength()), new ASN1Integer(pssSpec.getTrailerField()));
+
+ return pssP.getEncoded("DER");
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PSSParameterSpec.class && currentSpec != null)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PSSParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
+ }
+
+ this.currentSpec = (PSSParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+ currentSpec = new PSSParameterSpec(
+ pssP.getHashAlgorithm().getAlgorithm().getId(),
+ pssP.getMaskGenAlgorithm().getAlgorithm().getId(),
+ new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+ pssP.getSaltLength().intValue(),
+ pssP.getTrailerField().intValue());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "PSS Parameters";
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
new file mode 100644
index 000000000..31772a14e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
@@ -0,0 +1,241 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.RSAPrivateKey;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+/**
+ * A provider representation for a RSA private key, with CRT factors included.
+ */
+public class BCRSAPrivateCrtKey
+ extends BCRSAPrivateKey
+ implements RSAPrivateCrtKey
+{
+ static final long serialVersionUID = 7834723820638524718L;
+
+ private BigInteger publicExponent;
+ private BigInteger primeP;
+ private BigInteger primeQ;
+ private BigInteger primeExponentP;
+ private BigInteger primeExponentQ;
+ private BigInteger crtCoefficient;
+
+ /**
+ * construct a private key from it's org.spongycastle.crypto equivalent.
+ *
+ * @param key the parameters object representing the private key.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKeyParameters key)
+ {
+ super(key);
+
+ this.publicExponent = key.getPublicExponent();
+ this.primeP = key.getP();
+ this.primeQ = key.getQ();
+ this.primeExponentP = key.getDP();
+ this.primeExponentQ = key.getDQ();
+ this.crtCoefficient = key.getQInv();
+ }
+
+ /**
+ * construct a private key from an RSAPrivateCrtKeySpec
+ *
+ * @param spec the spec to be used in construction.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ this.privateExponent = spec.getPrivateExponent();
+ this.primeP = spec.getPrimeP();
+ this.primeQ = spec.getPrimeQ();
+ this.primeExponentP = spec.getPrimeExponentP();
+ this.primeExponentQ = spec.getPrimeExponentQ();
+ this.crtCoefficient = spec.getCrtCoefficient();
+ }
+
+ /**
+ * construct a private key from another RSAPrivateCrtKey.
+ *
+ * @param key the object implementing the RSAPrivateCrtKey interface.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrimeP();
+ this.primeQ = key.getPrimeQ();
+ this.primeExponentP = key.getPrimeExponentP();
+ this.primeExponentQ = key.getPrimeExponentQ();
+ this.crtCoefficient = key.getCrtCoefficient();
+ }
+
+ /**
+ * construct an RSA key from a private key info object.
+ */
+ BCRSAPrivateCrtKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ this(RSAPrivateKey.getInstance(info.parsePrivateKey()));
+ }
+
+ /**
+ * construct an RSA key from a ASN.1 RSA private key object.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrime1();
+ this.primeQ = key.getPrime2();
+ this.primeExponentP = key.getExponent1();
+ this.primeExponentQ = key.getExponent2();
+ this.crtCoefficient = key.getCoefficient();
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the encoding format we produce in getEncoded().
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ /**
+ * return the prime P.
+ *
+ * @return the prime P.
+ */
+ public BigInteger getPrimeP()
+ {
+ return primeP;
+ }
+
+ /**
+ * return the prime Q.
+ *
+ * @return the prime Q.
+ */
+ public BigInteger getPrimeQ()
+ {
+ return primeQ;
+ }
+
+ /**
+ * return the prime exponent for P.
+ *
+ * @return the prime exponent for P.
+ */
+ public BigInteger getPrimeExponentP()
+ {
+ return primeExponentP;
+ }
+
+ /**
+ * return the prime exponent for Q.
+ *
+ * @return the prime exponent for Q.
+ */
+ public BigInteger getPrimeExponentQ()
+ {
+ return primeExponentQ;
+ }
+
+ /**
+ * return the CRT coefficient.
+ *
+ * @return the CRT coefficient.
+ */
+ public BigInteger getCrtCoefficient()
+ {
+ return crtCoefficient;
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode()
+ ^ this.getPublicExponent().hashCode()
+ ^ this.getPrivateExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPrivateCrtKey))
+ {
+ return false;
+ }
+
+ RSAPrivateCrtKey key = (RSAPrivateCrtKey)o;
+
+ return this.getModulus().equals(key.getModulus())
+ && this.getPublicExponent().equals(key.getPublicExponent())
+ && this.getPrivateExponent().equals(key.getPrivateExponent())
+ && this.getPrimeP().equals(key.getPrimeP())
+ && this.getPrimeQ().equals(key.getPrimeQ())
+ && this.getPrimeExponentP().equals(key.getPrimeExponentP())
+ && this.getPrimeExponentQ().equals(key.getPrimeExponentQ())
+ && this.getCrtCoefficient().equals(key.getCrtCoefficient());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Private CRT Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+ buf.append(" private exponent: ").append(this.getPrivateExponent().toString(16)).append(nl);
+ buf.append(" primeP: ").append(this.getPrimeP().toString(16)).append(nl);
+ buf.append(" primeQ: ").append(this.getPrimeQ().toString(16)).append(nl);
+ buf.append(" primeExponentP: ").append(this.getPrimeExponentP().toString(16)).append(nl);
+ buf.append(" primeExponentQ: ").append(this.getPrimeExponentQ().toString(16)).append(nl);
+ buf.append(" crtCoefficient: ").append(this.getCrtCoefficient().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
new file mode 100644
index 000000000..e76e087b3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
@@ -0,0 +1,139 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class BCRSAPrivateKey
+ implements RSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 5110188922551353628L;
+
+ private static BigInteger ZERO = BigInteger.valueOf(0);
+
+ protected BigInteger modulus;
+ protected BigInteger privateExponent;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCRSAPrivateKey()
+ {
+ }
+
+ BCRSAPrivateKey(
+ RSAKeyParameters key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getExponent();
+ }
+
+ BCRSAPrivateKey(
+ RSAPrivateKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.privateExponent = spec.getPrivateExponent();
+ }
+
+ BCRSAPrivateKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getPrivateExponent();
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPrivateExponent()
+ {
+ return privateExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.spongycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof RSAPrivateKey))
+ {
+ return false;
+ }
+
+ if (o == this)
+ {
+ return true;
+ }
+
+ RSAPrivateKey key = (RSAPrivateKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPrivateExponent().equals(key.getPrivateExponent());
+ }
+
+ public int hashCode()
+ {
+ return getModulus().hashCode() ^ getPrivateExponent().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
new file mode 100644
index 000000000..bff5aac65
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
@@ -0,0 +1,172 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCRSAPublicKey
+ implements RSAPublicKey
+{
+ private static final AlgorithmIdentifier DEFAULT_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+
+ static final long serialVersionUID = 2675817738516720772L;
+
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+ private transient AlgorithmIdentifier algorithmIdentifier;
+
+ BCRSAPublicKey(
+ RSAKeyParameters key)
+ {
+ this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getExponent();
+ }
+
+ BCRSAPublicKey(
+ RSAPublicKeySpec spec)
+ {
+ this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ }
+
+ BCRSAPublicKey(
+ RSAPublicKey key)
+ {
+ this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ }
+
+ BCRSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ populateFromPublicKeyInfo(info);
+ }
+
+ private void populateFromPublicKeyInfo(SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ org.spongycastle.asn1.pkcs.RSAPublicKey pubKey = org.spongycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey());
+
+ this.algorithmIdentifier = info.getAlgorithm();
+ this.modulus = pubKey.getModulus();
+ this.publicExponent = pubKey.getPublicExponent();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in RSA public key");
+ }
+ }
+
+ /**
+ * return the modulus.
+ *
+ * @return the modulus.
+ */
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, new org.spongycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPublicKey))
+ {
+ return false;
+ }
+
+ RSAPublicKey key = (RSAPublicKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPublicExponent().equals(key.getPublicExponent());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Public Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ try
+ {
+ algorithmIdentifier = AlgorithmIdentifier.getInstance(in.readObject());
+ }
+ catch (OptionalDataException e)
+ {
+ algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ }
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ if (!algorithmIdentifier.equals(DEFAULT_ALGORITHM_IDENTIFIER))
+ {
+ out.writeObject(algorithmIdentifier.getEncoded());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
new file mode 100644
index 000000000..6e1a928d0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -0,0 +1,586 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.encodings.ISO9796d1Encoding;
+import org.spongycastle.crypto.encodings.OAEPEncoding;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.spongycastle.jcajce.provider.util.DigestFactory;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class CipherSpi
+ extends BaseCipherSpi
+{
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmParameterSpec paramSpec;
+ private AlgorithmParameters engineParams;
+ private boolean publicKeyOnly = false;
+ private boolean privateKeyOnly = false;
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public CipherSpi(
+ AsymmetricBlockCipher engine)
+ {
+ cipher = engine;
+ }
+
+ public CipherSpi(
+ OAEPParameterSpec pSpec)
+ {
+ try
+ {
+ initFromSpec(pSpec);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ public CipherSpi(
+ boolean publicKeyOnly,
+ boolean privateKeyOnly,
+ AsymmetricBlockCipher engine)
+ {
+ this.publicKeyOnly = publicKeyOnly;
+ this.privateKeyOnly = privateKeyOnly;
+ cipher = engine;
+ }
+
+ private void initFromSpec(
+ OAEPParameterSpec pSpec)
+ throws NoSuchPaddingException
+ {
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)pSpec.getMGFParameters();
+ Digest digest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (digest == null)
+ {
+ throw new NoSuchPaddingException("no match on OAEP constructor for digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ cipher = new OAEPEncoding(new RSABlindedEngine(), digest, ((PSource.PSpecified)pSpec.getPSource()).getValue());
+ paramSpec = pSpec;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ try
+ {
+ return cipher.getInputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (key instanceof RSAPrivateKey)
+ {
+ RSAPrivateKey k = (RSAPrivateKey)key;
+
+ return k.getModulus().bitLength();
+ }
+ else if (key instanceof RSAPublicKey)
+ {
+ RSAPublicKey k = (RSAPublicKey)key;
+
+ return k.getModulus().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an RSA key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ try
+ {
+ return cipher.getOutputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ String md = Strings.toUpperCase(mode);
+
+ if (md.equals("NONE") || md.equals("ECB"))
+ {
+ return;
+ }
+
+ if (md.equals("1"))
+ {
+ privateKeyOnly = true;
+ publicKeyOnly = false;
+ return;
+ }
+ else if (md.equals("2"))
+ {
+ privateKeyOnly = false;
+ publicKeyOnly = true;
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String pad = Strings.toUpperCase(padding);
+
+ if (pad.equals("NOPADDING"))
+ {
+ cipher = new RSABlindedEngine();
+ }
+ else if (pad.equals("PKCS1PADDING"))
+ {
+ cipher = new PKCS1Encoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("ISO9796-1PADDING"))
+ {
+ cipher = new ISO9796d1Encoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("MD5", "MGF1", new MGF1ParameterSpec("MD5"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPPADDING"))
+ {
+ initFromSpec(OAEPParameterSpec.DEFAULT);
+ }
+ else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-1ANDMGF1PADDING"))
+ {
+ initFromSpec(OAEPParameterSpec.DEFAULT);
+ }
+ else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-256ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-384ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-512ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
+ }
+ else
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (params == null || params instanceof OAEPParameterSpec)
+ {
+ if (key instanceof RSAPublicKey)
+ {
+ if (privateKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 1 requires RSAPrivateKey");
+ }
+
+ param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)key);
+ }
+ else if (key instanceof RSAPrivateKey)
+ {
+ if (publicKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 2 requires RSAPublicKey");
+ }
+
+ param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)key);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown key type passed to RSA");
+ }
+
+ if (params != null)
+ {
+ OAEPParameterSpec spec = (OAEPParameterSpec)params;
+
+ paramSpec = params;
+
+ if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1") && !spec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+ {
+ throw new InvalidAlgorithmParameterException("unknown mask generation function specified");
+ }
+
+ if (!(spec.getMGFParameters() instanceof MGF1ParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("unkown MGF parameters");
+ }
+
+ Digest digest = DigestFactory.getDigest(spec.getDigestAlgorithm());
+
+ if (digest == null)
+ {
+ throw new InvalidAlgorithmParameterException("no match on digest algorithm: "+ spec.getDigestAlgorithm());
+ }
+
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)spec.getMGFParameters();
+ Digest mgfDigest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (mgfDigest == null)
+ {
+ throw new InvalidAlgorithmParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ cipher = new OAEPEncoding(new RSABlindedEngine(), digest, mgfDigest, ((PSource.PSpecified)spec.getPSource()).getValue());
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown parameter type.");
+ }
+
+ if (!(cipher instanceof RSABlindedEngine))
+ {
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+ else
+ {
+ param = new ParametersWithRandom(param, new SecureRandom());
+ }
+ }
+
+ bOut.reset();
+
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed to RSA");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(OAEPParameterSpec.class);
+ }
+ catch (InvalidParameterSpecException e)
+ {
+ throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString(), e);
+ }
+ }
+
+ engineParams = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // this shouldn't happen
+ throw new InvalidKeyException("Eeeek! " + e.toString(), e);
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ byte[] out;
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ out = cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ finally
+ {
+ bOut.reset();
+ }
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+
+ /**
+ * classes that inherit from us.
+ */
+
+ static public class NoPadding
+ extends CipherSpi
+ {
+ public NoPadding()
+ {
+ super(new RSABlindedEngine());
+ }
+ }
+
+ static public class PKCS1v1_5Padding
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding()
+ {
+ super(new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class PKCS1v1_5Padding_PrivateOnly
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding_PrivateOnly()
+ {
+ super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class PKCS1v1_5Padding_PublicOnly
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding_PublicOnly()
+ {
+ super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class OAEPPadding
+ extends CipherSpi
+ {
+ public OAEPPadding()
+ {
+ super(OAEPParameterSpec.DEFAULT);
+ }
+ }
+
+ static public class ISO9796d1Padding
+ extends CipherSpi
+ {
+ public ISO9796d1Padding()
+ {
+ super(new ISO9796d1Encoding(new RSABlindedEngine()));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
new file mode 100644
index 000000000..90e3667c8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -0,0 +1,366 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+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.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.MD2Digest;
+import org.spongycastle.crypto.digests.MD4Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.NullDigest;
+import org.spongycastle.crypto.digests.RIPEMD128Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.RIPEMD256Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+
+public class DigestSignatureSpi
+ extends SignatureSpi
+{
+ private Digest digest;
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmIdentifier algId;
+
+ // care - this constructor is actually used by outside organisations
+ protected DigestSignatureSpi(
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ this.algId = null;
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected DigestSignatureSpi(
+ ASN1ObjectIdentifier objId,
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ this.algId = new AlgorithmIdentifier(objId, DERNull.INSTANCE);
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key (" + getType(publicKey) + ") is not a RSAPublicKey instance");
+ }
+
+ CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance");
+ }
+
+ CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ digest.reset();
+
+ cipher.init(true, param);
+ }
+
+ private String getType(
+ Object o)
+ {
+ if (o == null)
+ {
+ return null;
+ }
+
+ return o.getClass().getName();
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] bytes = derEncode(hash);
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new SignatureException("key too small for signature type");
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = cipher.processBlock(sigBytes, 0, sigBytes.length);
+
+ expected = derEncode(hash);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if (sig.length == expected.length)
+ {
+ for (int i = 0; i < sig.length; i++)
+ {
+ if (sig[i] != expected[i])
+ {
+ return false;
+ }
+ }
+ }
+ else if (sig.length == expected.length - 2) // NULL left out
+ {
+ int sigOffset = sig.length - hash.length - 2;
+ int expectedOffset = expected.length - hash.length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ for (int i = 0; i < hash.length; i++)
+ {
+ if (sig[sigOffset + i] != expected[expectedOffset + i]) // check hash
+ {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ if (sig[i] != expected[i]) // check header less NULL
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ return null;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return null;
+ }
+
+ private byte[] derEncode(
+ byte[] hash)
+ throws IOException
+ {
+ if (algId == null)
+ {
+ // For raw RSA, the DigestInfo must be prepared externally
+ return hash;
+ }
+
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.getEncoded(ASN1Encoding.DER);
+ }
+
+ static public class SHA1
+ extends DigestSignatureSpi
+ {
+ public SHA1()
+ {
+ super(OIWObjectIdentifiers.idSHA1, new SHA1Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA224
+ extends DigestSignatureSpi
+ {
+ public SHA224()
+ {
+ super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA256
+ extends DigestSignatureSpi
+ {
+ public SHA256()
+ {
+ super(NISTObjectIdentifiers.id_sha256, new SHA256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA384
+ extends DigestSignatureSpi
+ {
+ public SHA384()
+ {
+ super(NISTObjectIdentifiers.id_sha384, new SHA384Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA512
+ extends DigestSignatureSpi
+ {
+ public SHA512()
+ {
+ super(NISTObjectIdentifiers.id_sha512, new SHA512Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD2
+ extends DigestSignatureSpi
+ {
+ public MD2()
+ {
+ super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD4
+ extends DigestSignatureSpi
+ {
+ public MD4()
+ {
+ super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD5
+ extends DigestSignatureSpi
+ {
+ public MD5()
+ {
+ super(PKCSObjectIdentifiers.md5, new MD5Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD160
+ extends DigestSignatureSpi
+ {
+ public RIPEMD160()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD128
+ extends DigestSignatureSpi
+ {
+ public RIPEMD128()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD256
+ extends DigestSignatureSpi
+ {
+ public RIPEMD256()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class noneRSA
+ extends DigestSignatureSpi
+ {
+ public noneRSA()
+ {
+ super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
new file mode 100644
index 000000000..9337e6b15
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
@@ -0,0 +1,142 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.security.InvalidKeyException;
+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.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.signers.ISO9796d2Signer;
+
+public class ISOSignatureSpi
+ extends SignatureSpi
+{
+ private ISO9796d2Signer signer;
+
+ protected ISOSignatureSpi(
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ signer = new ISO9796d2Signer(cipher, digest, true);
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ signer.init(true, param);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ signer.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ signer.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ byte[] sig = signer.generateSignature();
+
+ return sig;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ boolean yes = signer.verifySignature(sigBytes);
+
+ return yes;
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ static public class SHA1WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public SHA1WithRSAEncryption()
+ {
+ super(new SHA1Digest(), new RSABlindedEngine());
+ }
+ }
+
+ static public class MD5WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public MD5WithRSAEncryption()
+ {
+ super(new MD5Digest(), new RSABlindedEngine());
+ }
+ }
+
+ static public class RIPEMD160WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public RIPEMD160WithRSAEncryption()
+ {
+ super(new RIPEMD160Digest(), new RSABlindedEngine());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
new file mode 100644
index 000000000..2b18b93b3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
@@ -0,0 +1,162 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.RSAPrivateKey;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(RSAPublicKeySpec.class) && key instanceof RSAPublicKey)
+ {
+ RSAPublicKey k = (RSAPublicKey)key;
+
+ return new RSAPublicKeySpec(k.getModulus(), k.getPublicExponent());
+ }
+ else if (spec.isAssignableFrom(RSAPrivateKeySpec.class) && key instanceof java.security.interfaces.RSAPrivateKey)
+ {
+ java.security.interfaces.RSAPrivateKey k = (java.security.interfaces.RSAPrivateKey)key;
+
+ return new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent());
+ }
+ else if (spec.isAssignableFrom(RSAPrivateCrtKeySpec.class) && key instanceof RSAPrivateCrtKey)
+ {
+ RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+ return new RSAPrivateCrtKeySpec(
+ k.getModulus(), k.getPublicExponent(),
+ k.getPrivateExponent(),
+ k.getPrimeP(), k.getPrimeQ(),
+ k.getPrimeExponentP(), k.getPrimeExponentQ(),
+ k.getCrtCoefficient());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof RSAPublicKey)
+ {
+ return new BCRSAPublicKey((RSAPublicKey)key);
+ }
+ else if (key instanceof RSAPrivateCrtKey)
+ {
+ return new BCRSAPrivateCrtKey((RSAPrivateCrtKey)key);
+ }
+ else if (key instanceof java.security.interfaces.RSAPrivateKey)
+ {
+ return new BCRSAPrivateKey((java.security.interfaces.RSAPrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+ }
+ catch (Exception e)
+ {
+ //
+ // in case it's just a RSAPrivateKey object... -- openSSL produces these
+ //
+ try
+ {
+ return new BCRSAPrivateCrtKey(
+ RSAPrivateKey.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+ }
+ catch (Exception ex)
+ {
+ throw new ExtendedInvalidKeySpecException("unable to process key spec: " + e.toString(), e);
+ }
+ }
+ }
+ else if (keySpec instanceof RSAPrivateCrtKeySpec)
+ {
+ return new BCRSAPrivateCrtKey((RSAPrivateCrtKeySpec)keySpec);
+ }
+ else if (keySpec instanceof RSAPrivateKeySpec)
+ {
+ return new BCRSAPrivateKey((RSAPrivateKeySpec)keySpec);
+ }
+
+ throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof RSAPublicKeySpec)
+ {
+ return new BCRSAPublicKey((RSAPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (RSAUtil.isRsaOid(algOid))
+ {
+ return new BCRSAPrivateCrtKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (RSAUtil.isRsaOid(algOid))
+ {
+ return new BCRSAPublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..1239628e1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,78 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.RSAKeyPairGenerator;
+import org.spongycastle.crypto.params.RSAKeyGenerationParameters;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ public KeyPairGeneratorSpi(
+ String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ final static BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);
+ final static int defaultTests = 12;
+
+ RSAKeyGenerationParameters param;
+ RSAKeyPairGenerator engine;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("RSA");
+
+ engine = new RSAKeyPairGenerator();
+ param = new RSAKeyGenerationParameters(defaultPublicExponent,
+ new SecureRandom(), 2048, defaultTests);
+ engine.init(param);
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ param = new RSAKeyGenerationParameters(defaultPublicExponent,
+ random, strength, defaultTests);
+
+ engine.init(param);
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof RSAKeyGenParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a RSAKeyGenParameterSpec");
+ }
+ RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
+
+ param = new RSAKeyGenerationParameters(
+ rsaParams.getPublicExponent(),
+ random, rsaParams.getKeysize(), defaultTests);
+
+ engine.init(param);
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ RSAKeyParameters pub = (RSAKeyParameters)pair.getPublic();
+ RSAPrivateCrtKeyParameters priv = (RSAPrivateCrtKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCRSAPublicKey(pub),
+ new BCRSAPrivateCrtKey(priv));
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
new file mode 100644
index 000000000..adce8b598
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
@@ -0,0 +1,394 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.util.DigestFactory;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class PSSSignatureSpi
+ extends SignatureSpi
+{
+ private AlgorithmParameters engineParams;
+ private PSSParameterSpec paramSpec;
+ private PSSParameterSpec originalSpec;
+ private AsymmetricBlockCipher signer;
+ private Digest contentDigest;
+ private Digest mgfDigest;
+ private int saltLength;
+ private byte trailer;
+ private boolean isRaw;
+
+ private org.spongycastle.crypto.signers.PSSSigner pss;
+
+ private byte getTrailer(
+ int trailerField)
+ {
+ if (trailerField == 1)
+ {
+ return org.spongycastle.crypto.signers.PSSSigner.TRAILER_IMPLICIT;
+ }
+
+ throw new IllegalArgumentException("unknown trailer field");
+ }
+
+ private void setupContentDigest()
+ {
+ if (isRaw)
+ {
+ this.contentDigest = new NullPssDigest(mgfDigest);
+ }
+ else
+ {
+ this.contentDigest = mgfDigest;
+ }
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected PSSSignatureSpi(
+ AsymmetricBlockCipher signer,
+ PSSParameterSpec paramSpecArg)
+ {
+ this(signer, paramSpecArg, false);
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected PSSSignatureSpi(
+ AsymmetricBlockCipher signer,
+ PSSParameterSpec baseParamSpec,
+ boolean isRaw)
+ {
+ this.signer = signer;
+ this.originalSpec = baseParamSpec;
+
+ if (baseParamSpec == null)
+ {
+ this.paramSpec = PSSParameterSpec.DEFAULT;
+ }
+ else
+ {
+ this.paramSpec = baseParamSpec;
+ }
+
+ this.mgfDigest = DigestFactory.getDigest(paramSpec.getDigestAlgorithm());
+ this.saltLength = paramSpec.getSaltLength();
+ this.trailer = getTrailer(paramSpec.getTrailerField());
+ this.isRaw = isRaw;
+
+ setupContentDigest();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPublicKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer);
+ pss.init(false,
+ RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey));
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer);
+ pss.init(true, new ParametersWithRandom(RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey), random));
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer);
+ pss.init(true, RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey));
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ pss.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ pss.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ return pss.generateSignature();
+ }
+ catch (CryptoException e)
+ {
+ throw new SignatureException(e.getMessage());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ return pss.verifySignature(sigBytes);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ throws InvalidParameterException
+ {
+ if (params instanceof PSSParameterSpec)
+ {
+ PSSParameterSpec newParamSpec = (PSSParameterSpec)params;
+
+ if (originalSpec != null)
+ {
+ if (!DigestFactory.isSameDigest(originalSpec.getDigestAlgorithm(), newParamSpec.getDigestAlgorithm()))
+ {
+ throw new InvalidParameterException("parameter must be using " + originalSpec.getDigestAlgorithm());
+ }
+ }
+ if (!newParamSpec.getMGFAlgorithm().equalsIgnoreCase("MGF1") && !newParamSpec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+ {
+ throw new InvalidParameterException("unknown mask generation function specified");
+ }
+
+ if (!(newParamSpec.getMGFParameters() instanceof MGF1ParameterSpec))
+ {
+ throw new InvalidParameterException("unkown MGF parameters");
+ }
+
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)newParamSpec.getMGFParameters();
+
+ if (!DigestFactory.isSameDigest(mgfParams.getDigestAlgorithm(), newParamSpec.getDigestAlgorithm()))
+ {
+ throw new InvalidParameterException("digest algorithm for MGF should be the same as for PSS parameters.");
+ }
+
+ Digest newDigest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (newDigest == null)
+ {
+ throw new InvalidParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ this.engineParams = null;
+ this.paramSpec = newParamSpec;
+ this.mgfDigest = newDigest;
+ this.saltLength = paramSpec.getSaltLength();
+ this.trailer = getTrailer(paramSpec.getTrailerField());
+
+ setupContentDigest();
+ }
+ else
+ {
+ throw new InvalidParameterException("Only PSSParameterSpec supported");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("PSS", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineGetParameter unsupported");
+ }
+
+ static public class nonePSS
+ extends PSSSignatureSpi
+ {
+ public nonePSS()
+ {
+ super(new RSABlindedEngine(), null, true);
+ }
+ }
+
+ static public class PSSwithRSA
+ extends PSSSignatureSpi
+ {
+ public PSSwithRSA()
+ {
+ super(new RSABlindedEngine(), null);
+ }
+ }
+
+ static public class SHA1withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA1withRSA()
+ {
+ super(new RSABlindedEngine(), PSSParameterSpec.DEFAULT);
+ }
+ }
+
+ static public class SHA224withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA224withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), 28, 1));
+ }
+ }
+
+ static public class SHA256withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA256withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1));
+ }
+ }
+
+ static public class SHA384withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA384withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA-384", "MGF1", new MGF1ParameterSpec("SHA-384"), 48, 1));
+ }
+ }
+
+ static public class SHA512withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA512withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512", "MGF1", new MGF1ParameterSpec("SHA-512"), 64, 1));
+ }
+ }
+
+ private class NullPssDigest
+ implements Digest
+ {
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ private Digest baseDigest;
+ private boolean oddTime = true;
+
+ public NullPssDigest(Digest mgfDigest)
+ {
+ this.baseDigest = mgfDigest;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "NULL";
+ }
+
+ public int getDigestSize()
+ {
+ return baseDigest.getDigestSize();
+ }
+
+ public void update(byte in)
+ {
+ bOut.write(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ bOut.write(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ byte[] res = bOut.toByteArray();
+
+ if (oddTime)
+ {
+ System.arraycopy(res, 0, out, outOff, res.length);
+ }
+ else
+ {
+ baseDigest.update(res, 0, res.length);
+
+ baseDigest.doFinal(out, outOff);
+ }
+
+ reset();
+
+ oddTime = !oddTime;
+
+ return res.length;
+ }
+
+ public void reset()
+ {
+ bOut.reset();
+ baseDigest.reset();
+ }
+
+ public int getByteLength()
+ {
+ return 0;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
new file mode 100644
index 000000000..da57ec3b6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
@@ -0,0 +1,66 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * utility class for converting java.security RSA objects into their
+ * org.spongycastle.crypto counterparts.
+ */
+public class RSAUtil
+{
+ public static final ASN1ObjectIdentifier[] rsaOids =
+ {
+ PKCSObjectIdentifiers.rsaEncryption,
+ X509ObjectIdentifiers.id_ea_rsa,
+ PKCSObjectIdentifiers.id_RSAES_OAEP,
+ PKCSObjectIdentifiers.id_RSASSA_PSS
+ };
+
+ public static boolean isRsaOid(
+ ASN1ObjectIdentifier algOid)
+ {
+ for (int i = 0; i != rsaOids.length; i++)
+ {
+ if (algOid.equals(rsaOids[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static RSAKeyParameters generatePublicKeyParameter(
+ RSAPublicKey key)
+ {
+ return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent());
+
+ }
+
+ static RSAKeyParameters generatePrivateKeyParameter(
+ RSAPrivateKey key)
+ {
+ if (key instanceof RSAPrivateCrtKey)
+ {
+ RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+ return new RSAPrivateCrtKeyParameters(k.getModulus(),
+ k.getPublicExponent(), k.getPrivateExponent(),
+ k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient());
+ }
+ else
+ {
+ RSAPrivateKey k = key;
+
+ return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
new file mode 100644
index 000000000..4c1ed0eeb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
@@ -0,0 +1,216 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public abstract class BaseCipherSpi
+ extends CipherSpi
+{
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ RC2ParameterSpec.class,
+ RC5ParameterSpec.class
+ };
+
+
+ protected AlgorithmParameters engineParams = null;
+
+ protected Wrapper wrapEngine = null;
+
+ private int ivSize;
+ private byte[] iv;
+
+ protected BaseCipherSpi()
+ {
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return 0;
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return -1;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return null;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+
+ protected byte[] engineWrap(
+ Key key)
+ throws IllegalBlockSizeException, InvalidKeyException
+ {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null)
+ {
+ throw new InvalidKeyException("Cannot wrap key, null encoding.");
+ }
+
+ try
+ {
+ if (wrapEngine == null)
+ {
+ return engineDoFinal(encoded, 0, encoded.length);
+ }
+ else
+ {
+ return wrapEngine.wrap(encoded, 0, encoded.length);
+ }
+ }
+ catch (BadPaddingException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ }
+
+ protected Key engineUnwrap(
+ byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException
+ {
+ byte[] encoded;
+ try
+ {
+ if (wrapEngine == null)
+ {
+ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ }
+ else
+ {
+ encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ catch (BadPaddingException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ catch (IllegalBlockSizeException e2)
+ {
+ throw new InvalidKeyException(e2.getMessage());
+ }
+
+ if (wrappedKeyType == Cipher.SECRET_KEY)
+ {
+ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+ }
+ else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ /*
+ * The caller doesn't know the algorithm as it is part of
+ * the encrypted data.
+ */
+ try
+ {
+ PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);
+
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+ if (privKey != null)
+ {
+ return privKey;
+ }
+ else
+ {
+ throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("Invalid key encoding.");
+ }
+ }
+ else
+ {
+ try
+ {
+ KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+ if (wrappedKeyType == Cipher.PUBLIC_KEY)
+ {
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ }
+ else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (InvalidKeySpecException e2)
+ {
+ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+ }
+
+ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
new file mode 100644
index 000000000..13231c51c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
@@ -0,0 +1,78 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.io.IOException;
+import java.security.Key;
+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 org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public abstract class BaseKeyFactorySpi
+ extends java.security.KeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException("encoded key spec not recognised");
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("key spec not recognised");
+ }
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof X509EncodedKeySpec)
+ {
+ try
+ {
+ return generatePublic(SubjectPublicKeyInfo.getInstance(((X509EncodedKeySpec)keySpec).getEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException("encoded key spec not recognised");
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("key spec not recognised");
+ }
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+
+ throw new InvalidKeySpecException("not implemented yet " + key + " " + spec);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DHUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DHUtil.java
new file mode 100644
index 000000000..10b633da7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DHUtil.java
@@ -0,0 +1,50 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.DHParameters;
+import org.spongycastle.crypto.params.DHPrivateKeyParameters;
+import org.spongycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DH objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class DHUtil
+{
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPublicKey)
+ {
+ DHPublicKey k = (DHPublicKey)key;
+
+ return new DHPublicKeyParameters(k.getY(),
+ new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+ }
+
+ throw new InvalidKeyException("can't identify DH public key.");
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)key;
+
+ return new DHPrivateKeyParameters(k.getX(),
+ new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+ }
+
+ throw new InvalidKeyException("can't identify DH private key.");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java
new file mode 100644
index 000000000..0f659b2c4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java
@@ -0,0 +1,112 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+
+public abstract class DSABase
+ extends SignatureSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ protected Digest digest;
+ protected DSA signer;
+ protected DSAEncoder encoder;
+
+ protected DSABase(
+ Digest digest,
+ DSA signer,
+ DSAEncoder encoder)
+ {
+ this.digest = digest;
+ this.signer = signer;
+ this.encoder = encoder;
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+
+ return encoder.encode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ sig = encoder.decode(sigBytes);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DSAEncoder.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
new file mode 100644
index 000000000..349641dd9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
@@ -0,0 +1,13 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public interface DSAEncoder
+{
+ byte[] encode(BigInteger r, BigInteger s)
+ throws IOException;
+
+ BigInteger[] decode(byte[] sig)
+ throws IOException;
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/EC5Util.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/EC5Util.java
new file mode 100644
index 000000000..b6fc1ee35
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/EC5Util.java
@@ -0,0 +1,123 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class EC5Util
+{
+ public static EllipticCurve convertCurve(
+ ECCurve curve,
+ byte[] seed)
+ {
+ // TODO: the Sun EC implementation doesn't currently handle the seed properly
+ // so at the moment it's set to null. Should probably look at making this configurable
+ if (curve instanceof ECCurve.Fp)
+ {
+ return new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
+ }
+ else
+ {
+ ECCurve.F2m curveF2m = (ECCurve.F2m)curve;
+ int ks[];
+
+ if (curveF2m.isTrinomial())
+ {
+ ks = new int[] { curveF2m.getK1() };
+
+ return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
+ }
+ else
+ {
+ ks = new int[] { curveF2m.getK3(), curveF2m.getK2(), curveF2m.getK1() };
+
+ return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
+ }
+ }
+ }
+
+ public static ECCurve convertCurve(
+ EllipticCurve ec)
+ {
+ ECField field = ec.getField();
+ BigInteger a = ec.getA();
+ BigInteger b = ec.getB();
+
+ if (field instanceof ECFieldFp)
+ {
+ return new ECCurve.Fp(((ECFieldFp)field).getP(), a, b);
+ }
+ else
+ {
+ ECFieldF2m fieldF2m = (ECFieldF2m)field;
+ int m = fieldF2m.getM();
+ int ks[] = ECUtil.convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
+ return new ECCurve.F2m(m, ks[0], ks[1], ks[2], a, b);
+ }
+ }
+
+ public static ECParameterSpec convertSpec(
+ EllipticCurve ellipticCurve,
+ org.spongycastle.jce.spec.ECParameterSpec spec)
+ {
+ if (spec instanceof ECNamedCurveParameterSpec)
+ {
+ return new ECNamedCurveSpec(
+ ((ECNamedCurveParameterSpec)spec).getName(),
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(),
+ spec.getH());
+ }
+ else
+ {
+ return new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(),
+ spec.getH().intValue());
+ }
+ }
+
+ public static org.spongycastle.jce.spec.ECParameterSpec convertSpec(
+ ECParameterSpec ecSpec,
+ boolean withCompression)
+ {
+ ECCurve curve = convertCurve(ecSpec.getCurve());
+
+ return new org.spongycastle.jce.spec.ECParameterSpec(
+ curve,
+ convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+ }
+
+ public static org.spongycastle.math.ec.ECPoint convertPoint(
+ ECParameterSpec ecSpec,
+ ECPoint point,
+ boolean withCompression)
+ {
+ return convertPoint(convertCurve(ecSpec.getCurve()), point, withCompression);
+ }
+
+ public static org.spongycastle.math.ec.ECPoint convertPoint(
+ ECCurve curve,
+ ECPoint point,
+ boolean withCompression)
+ {
+ return curve.createPoint(point.getAffineX(), point.getAffineY(), withCompression);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java
new file mode 100644
index 000000000..b84c7ad55
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java
@@ -0,0 +1,286 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.sec.SECNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962NamedCurves;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+/**
+ * utility class for converting jce/jca ECDSA, ECDH, and ECDHC
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class ECUtil
+{
+ /**
+ * Returns a sorted array of middle terms of the reduction polynomial.
+ * @param k The unsorted array of middle terms of the reduction polynomial
+ * of length 1 or 3.
+ * @return the sorted array of middle terms of the reduction polynomial.
+ * This array always has length 3.
+ */
+ static int[] convertMidTerms(
+ int[] k)
+ {
+ int[] res = new int[3];
+
+ if (k.length == 1)
+ {
+ res[0] = k[0];
+ }
+ else
+ {
+ if (k.length != 3)
+ {
+ throw new IllegalArgumentException("Only Trinomials and pentanomials supported");
+ }
+
+ if (k[0] < k[1] && k[0] < k[2])
+ {
+ res[0] = k[0];
+ if (k[1] < k[2])
+ {
+ res[1] = k[1];
+ res[2] = k[2];
+ }
+ else
+ {
+ res[1] = k[2];
+ res[2] = k[1];
+ }
+ }
+ else if (k[1] < k[2])
+ {
+ res[0] = k[1];
+ if (k[0] < k[2])
+ {
+ res[1] = k[0];
+ res[2] = k[2];
+ }
+ else
+ {
+ res[1] = k[2];
+ res[2] = k[0];
+ }
+ }
+ else
+ {
+ res[0] = k[2];
+ if (k[0] < k[1])
+ {
+ res[1] = k[0];
+ res[2] = k[1];
+ }
+ else
+ {
+ res[1] = k[1];
+ res[2] = k[0];
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public static AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ ECParameterSpec s = k.getParameters();
+
+ if (s == null)
+ {
+ s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new ECPublicKeyParameters(
+ ((BCECPublicKey)k).engineGetQ(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ else
+ {
+ return new ECPublicKeyParameters(
+ k.getQ(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ }
+ else if (key instanceof java.security.interfaces.ECPublicKey)
+ {
+ java.security.interfaces.ECPublicKey pubKey = (java.security.interfaces.ECPublicKey)key;
+ ECParameterSpec s = EC5Util.convertSpec(pubKey.getParams(), false);
+ return new ECPublicKeyParameters(
+ EC5Util.convertPoint(pubKey.getParams(), pubKey.getW(), false),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ else
+ {
+ // see if we can build a key from key.getEncoded()
+ try
+ {
+ byte[] bytes = key.getEncoded();
+
+ if (bytes == null)
+ {
+ throw new InvalidKeyException("no encoding for EC public key");
+ }
+
+ PublicKey publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof java.security.interfaces.ECPublicKey)
+ {
+ return ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("cannot identify EC public key: " + e.toString());
+ }
+ }
+
+ throw new InvalidKeyException("cannot identify EC public key.");
+ }
+
+ public static AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+ ECParameterSpec s = k.getParameters();
+
+ if (s == null)
+ {
+ s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ return new ECPrivateKeyParameters(
+ k.getD(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ else if (key instanceof java.security.interfaces.ECPrivateKey)
+ {
+ java.security.interfaces.ECPrivateKey privKey = (java.security.interfaces.ECPrivateKey)key;
+ ECParameterSpec s = EC5Util.convertSpec(privKey.getParams(), false);
+ return new ECPrivateKeyParameters(
+ privKey.getS(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ else
+ {
+ // see if we can build a key from key.getEncoded()
+ try
+ {
+ byte[] bytes = key.getEncoded();
+
+ if (bytes == null)
+ {
+ throw new InvalidKeyException("no encoding for EC private key");
+ }
+
+ PrivateKey privateKey = BouncyCastleProvider.getPrivateKey(PrivateKeyInfo.getInstance(bytes));
+
+ if (privateKey instanceof java.security.interfaces.ECPrivateKey)
+ {
+ return ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("cannot identify EC private key: " + e.toString());
+ }
+ }
+
+ throw new InvalidKeyException("can't identify EC private key.");
+ }
+
+ public static ASN1ObjectIdentifier getNamedCurveOid(
+ String name)
+ {
+ ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name);
+
+ if (oid == null)
+ {
+ oid = SECNamedCurves.getOID(name);
+ if (oid == null)
+ {
+ oid = NISTNamedCurves.getOID(name);
+ }
+ if (oid == null)
+ {
+ oid = TeleTrusTNamedCurves.getOID(name);
+ }
+ if (oid == null)
+ {
+ oid = ECGOST3410NamedCurves.getOID(name);
+ }
+ }
+
+ return oid;
+ }
+
+ public static X9ECParameters getNamedCurveByOid(
+ ASN1ObjectIdentifier oid)
+ {
+ X9ECParameters params = X962NamedCurves.getByOID(oid);
+
+ if (params == null)
+ {
+ params = SECNamedCurves.getByOID(oid);
+ if (params == null)
+ {
+ params = NISTNamedCurves.getByOID(oid);
+ }
+ if (params == null)
+ {
+ params = TeleTrusTNamedCurves.getByOID(oid);
+ }
+ }
+
+ return params;
+ }
+
+ public static String getCurveName(
+ ASN1ObjectIdentifier oid)
+ {
+ String name = X962NamedCurves.getName(oid);
+
+ if (name == null)
+ {
+ name = SECNamedCurves.getName(oid);
+ if (name == null)
+ {
+ name = NISTNamedCurves.getName(oid);
+ }
+ if (name == null)
+ {
+ name = TeleTrusTNamedCurves.getName(oid);
+ }
+ if (name == null)
+ {
+ name = ECGOST3410NamedCurves.getName(oid);
+ }
+ }
+
+ return name;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java
new file mode 100644
index 000000000..3f39d39e5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java
@@ -0,0 +1,21 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.security.spec.InvalidKeySpecException;
+
+public class ExtendedInvalidKeySpecException
+ extends InvalidKeySpecException
+{
+ private Throwable cause;
+
+ public ExtendedInvalidKeySpecException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/GOST3410Util.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/GOST3410Util.java
new file mode 100644
index 000000000..c331e3c01
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/GOST3410Util.java
@@ -0,0 +1,52 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.GOST3410Parameters;
+import org.spongycastle.crypto.params.GOST3410PrivateKeyParameters;
+import org.spongycastle.crypto.params.GOST3410PublicKeyParameters;
+import org.spongycastle.jce.interfaces.GOST3410PrivateKey;
+import org.spongycastle.jce.interfaces.GOST3410PublicKey;
+import org.spongycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+
+/**
+ * utility class for converting jce/jca GOST3410-94 objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class GOST3410Util
+{
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof GOST3410PublicKey)
+ {
+ GOST3410PublicKey k = (GOST3410PublicKey)key;
+ GOST3410PublicKeyParameterSetSpec p = k.getParameters().getPublicKeyParameters();
+
+ return new GOST3410PublicKeyParameters(k.getY(),
+ new GOST3410Parameters(p.getP(), p.getQ(), p.getA()));
+ }
+
+ throw new InvalidKeyException("can't identify GOST3410 public key: " + key.getClass().getName());
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof GOST3410PrivateKey)
+ {
+ GOST3410PrivateKey k = (GOST3410PrivateKey)key;
+ GOST3410PublicKeyParameterSetSpec p = k.getParameters().getPublicKeyParameters();
+
+ return new GOST3410PrivateKeyParameters(k.getX(),
+ new GOST3410Parameters(p.getP(), p.getQ(), p.getA()));
+ }
+
+ throw new InvalidKeyException("can't identify GOST3410 private key.");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/IESUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/IESUtil.java
new file mode 100644
index 000000000..fb93838e6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/IESUtil.java
@@ -0,0 +1,32 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import org.spongycastle.crypto.engines.IESEngine;
+import org.spongycastle.jce.spec.IESParameterSpec;
+
+public class IESUtil
+{
+ public static IESParameterSpec guessParameterSpec(IESEngine engine)
+ {
+ if (engine.getCipher() == null)
+ {
+ return new IESParameterSpec(null, null, 128);
+ }
+ else if (engine.getCipher().getUnderlyingCipher().getAlgorithmName().equals("DES") ||
+ engine.getCipher().getUnderlyingCipher().getAlgorithmName().equals("RC2") ||
+ engine.getCipher().getUnderlyingCipher().getAlgorithmName().equals("RC5-32") ||
+ engine.getCipher().getUnderlyingCipher().getAlgorithmName().equals("RC5-64"))
+ {
+ return new IESParameterSpec(null, null, 64, 64);
+ }
+ else if (engine.getCipher().getUnderlyingCipher().getAlgorithmName().equals("SKIPJACK"))
+ {
+ return new IESParameterSpec(null, null, 80, 80);
+ }
+ else if (engine.getCipher().getUnderlyingCipher().getAlgorithmName().equals("GOST28147"))
+ {
+ return new IESParameterSpec(null, null, 256, 256);
+ }
+
+ return new IESParameterSpec(null, null, 128, 128);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/KeyUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/KeyUtil.java
new file mode 100644
index 000000000..d1eb68413
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/KeyUtil.java
@@ -0,0 +1,72 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public class KeyUtil
+{
+ public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, ASN1Encodable keyData)
+ {
+ try
+ {
+ return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, byte[] keyData)
+ {
+ try
+ {
+ return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedSubjectPublicKeyInfo(SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedPrivateKeyInfo(AlgorithmIdentifier algId, ASN1Encodable privKey)
+ {
+ try
+ {
+ PrivateKeyInfo info = new PrivateKeyInfo(algId, privKey.toASN1Primitive());
+
+ return getEncodedPrivateKeyInfo(info);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedPrivateKeyInfo(PrivateKeyInfo info)
+ {
+ try
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
new file mode 100644
index 000000000..b46e1cf4c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
@@ -0,0 +1,125 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class PKCS12BagAttributeCarrierImpl
+ implements PKCS12BagAttributeCarrier
+{
+ private Hashtable pkcs12Attributes;
+ private Vector pkcs12Ordering;
+
+ PKCS12BagAttributeCarrierImpl(Hashtable attributes, Vector ordering)
+ {
+ this.pkcs12Attributes = attributes;
+ this.pkcs12Ordering = ordering;
+ }
+
+ public PKCS12BagAttributeCarrierImpl()
+ {
+ this(new Hashtable(), new Vector());
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ if (pkcs12Attributes.containsKey(oid))
+ { // preserve original ordering
+ pkcs12Attributes.put(oid, attribute);
+ }
+ else
+ {
+ pkcs12Attributes.put(oid, attribute);
+ pkcs12Ordering.addElement(oid);
+ }
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return (ASN1Encodable)pkcs12Attributes.get(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return pkcs12Ordering.elements();
+ }
+
+ int size()
+ {
+ return pkcs12Ordering.size();
+ }
+
+ Hashtable getAttributes()
+ {
+ return pkcs12Attributes;
+ }
+
+ Vector getOrdering()
+ {
+ return pkcs12Ordering;
+ }
+
+ public void writeObject(ObjectOutputStream out)
+ throws IOException
+ {
+ if (pkcs12Ordering.size() == 0)
+ {
+ out.writeObject(new Hashtable());
+ out.writeObject(new Vector());
+ }
+ else
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ Enumeration e = this.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+
+ aOut.writeObject(oid);
+ aOut.writeObject((ASN1Encodable)pkcs12Attributes.get(oid));
+ }
+
+ out.writeObject(bOut.toByteArray());
+ }
+ }
+
+ public void readObject(ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ Object obj = in.readObject();
+
+ if (obj instanceof Hashtable)
+ {
+ this.pkcs12Attributes = (Hashtable)obj;
+ this.pkcs12Ordering = (Vector)in.readObject();
+ }
+ else
+ {
+ ASN1InputStream aIn = new ASN1InputStream((byte[])obj);
+
+ ASN1ObjectIdentifier oid;
+
+ while ((oid = (ASN1ObjectIdentifier)aIn.readObject()) != null)
+ {
+ this.setBagAttribute(oid, aIn.readObject());
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
new file mode 100644
index 000000000..1d1dc8c9d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
@@ -0,0 +1,395 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+
+/**
+ * class for dealing with X509 certificates.
+ * <p>
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+public class CertificateFactory
+ extends CertificateFactorySpi
+{
+ private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
+ private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
+
+ private ASN1Set sData = null;
+ private int sDataObjectCount = 0;
+ private InputStream currentStream = null;
+
+ private ASN1Set sCrlData = null;
+ private int sCrlDataObjectCount = 0;
+ private InputStream currentCrlStream = null;
+
+ private java.security.cert.Certificate readDERCertificate(
+ ASN1InputStream dIn)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+
+ return getCertificate();
+ }
+ }
+
+ return new X509CertificateObject(
+ Certificate.getInstance(seq));
+ }
+
+ private java.security.cert.Certificate getCertificate()
+ throws CertificateParsingException
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.size())
+ {
+ Object obj = sData.getObjectAt(sDataObjectCount++);
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new X509CertificateObject(
+ Certificate.getInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private java.security.cert.Certificate readPEMCertificate(
+ InputStream in)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return new X509CertificateObject(
+ Certificate.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ protected CRL createCRL(CertificateList c)
+ throws CRLException
+ {
+ return new X509CRLObject(c);
+ }
+
+ private CRL readPEMCRL(
+ InputStream in)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ private CRL readDERCRL(
+ ASN1InputStream aIn)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = (ASN1Sequence)aIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sCrlData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
+
+ return getCRL();
+ }
+ }
+
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ private CRL getCRL()
+ throws CRLException
+ {
+ if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size())
+ {
+ return null;
+ }
+
+ return createCRL(
+ CertificateList.getInstance(
+ sCrlData.getObjectAt(sCrlDataObjectCount++)));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public java.security.cert.Certificate engineGenerateCertificate(
+ InputStream in)
+ throws CertificateException
+ {
+ if (currentStream == null)
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != in) // reset if input stream has changed
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.size())
+ {
+ return getCertificate();
+ }
+ else
+ {
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(in);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCertificate(pis);
+ }
+ else
+ {
+ return readDERCertificate(new ASN1InputStream(pis));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExCertificateException(e);
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public Collection engineGenerateCertificates(
+ InputStream inStream)
+ throws CertificateException
+ {
+ java.security.cert.Certificate cert;
+ List certs = new ArrayList();
+
+ while ((cert = engineGenerateCertificate(inStream)) != null)
+ {
+ certs.add(cert);
+ }
+
+ return certs;
+ }
+
+ /**
+ * Generates a certificate revocation list (CRL) object and initializes
+ * it with the data read from the input stream inStream.
+ */
+ public CRL engineGenerateCRL(
+ InputStream inStream)
+ throws CRLException
+ {
+ if (currentCrlStream == null)
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+ else if (currentCrlStream != inStream) // reset if input stream has changed
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sCrlData != null)
+ {
+ if (sCrlDataObjectCount != sCrlData.size())
+ {
+ return getCRL();
+ }
+ else
+ {
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(inStream);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCRL(pis);
+ }
+ else
+ { // lazy evaluate to help processing of large CRLs
+ return readDERCRL(new ASN1InputStream(pis, true));
+ }
+ }
+ catch (CRLException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the CRLs read from
+ * the given input stream inStream.
+ *
+ * The inStream may contain a sequence of DER-encoded CRLs, or
+ * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
+ * only signficant field being crls. In particular the signature
+ * and the contents are ignored.
+ */
+ public Collection engineGenerateCRLs(
+ InputStream inStream)
+ throws CRLException
+ {
+ CRL crl;
+ List crls = new ArrayList();
+
+ while ((crl = engineGenerateCRL(inStream)) != null)
+ {
+ crls.add(crl);
+ }
+
+ return crls;
+ }
+
+ public Iterator engineGetCertPathEncodings()
+ {
+ return PKIXCertPath.certPathEncodings.iterator();
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream)
+ throws CertificateException
+ {
+ return engineGenerateCertPath(inStream, "PkiPath");
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ return new PKIXCertPath(inStream, encoding);
+ }
+
+ public CertPath engineGenerateCertPath(
+ List certificates)
+ throws CertificateException
+ {
+ Iterator iter = certificates.iterator();
+ Object obj;
+ while (iter.hasNext())
+ {
+ obj = iter.next();
+ if (obj != null)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ throw new CertificateException("list contains non X509Certificate object while creating CertPath\n" + obj.toString());
+ }
+ }
+ }
+ return new PKIXCertPath(certificates);
+ }
+
+ private class ExCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public ExCertificateException(Throwable cause)
+ {
+ this.cause = cause;
+ }
+
+ public ExCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java
new file mode 100644
index 000000000..af366acf5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/ExtCRLException.java
@@ -0,0 +1,20 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.security.cert.CRLException;
+
+class ExtCRLException
+ extends CRLException
+{
+ Throwable cause;
+
+ ExtCRLException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/KeyFactory.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/KeyFactory.java
new file mode 100644
index 000000000..385970485
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/KeyFactory.java
@@ -0,0 +1,95 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+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 org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class KeyFactory
+ extends KeyFactorySpi
+{
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ try
+ {
+ PrivateKeyInfo info = PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded());
+ PrivateKey key = BouncyCastleProvider.getPrivateKey(info);
+
+ if (key != null)
+ {
+ return key;
+ }
+
+ throw new InvalidKeySpecException("no factory found for OID: " + info.getPrivateKeyAlgorithm().getAlgorithm());
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof X509EncodedKeySpec)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(((X509EncodedKeySpec)keySpec).getEncoded());
+ PublicKey key = BouncyCastleProvider.getPublicKey(info);
+
+ if (key != null)
+ {
+ return key;
+ }
+
+ throw new InvalidKeySpecException("no factory found for OID: " + info.getAlgorithm().getAlgorithm());
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+ }
+
+ protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+
+ throw new InvalidKeySpecException("not implemented yet " + key + " " + keySpec);
+ }
+
+ protected Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ throw new InvalidKeyException("not implemented yet " + key);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/PEMUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
new file mode 100644
index 000000000..acc6d0356
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
@@ -0,0 +1,93 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.util.encoders.Base64;
+
+public class PEMUtil
+{
+ private final String _header1;
+ private final String _header2;
+ private final String _footer1;
+ private final String _footer2;
+
+ PEMUtil(
+ String type)
+ {
+ _header1 = "-----BEGIN " + type + "-----";
+ _header2 = "-----BEGIN X509 " + type + "-----";
+ _footer1 = "-----END " + type + "-----";
+ _footer2 = "-----END X509 " + type + "-----";
+ }
+
+ private String readLine(
+ InputStream in)
+ throws IOException
+ {
+ int c;
+ StringBuffer l = new StringBuffer();
+
+ do
+ {
+ while (((c = in.read()) != '\r') && c != '\n' && (c >= 0))
+ {
+ if (c == '\r')
+ {
+ continue;
+ }
+
+ l.append((char)c);
+ }
+ }
+ while (c >= 0 && l.length() == 0);
+
+ if (c < 0)
+ {
+ return null;
+ }
+
+ return l.toString();
+ }
+
+ ASN1Sequence readPEMObject(
+ InputStream in)
+ throws IOException
+ {
+ String line;
+ StringBuffer pemBuf = new StringBuffer();
+
+ while ((line = readLine(in)) != null)
+ {
+ if (line.startsWith(_header1) || line.startsWith(_header2))
+ {
+ break;
+ }
+ }
+
+ while ((line = readLine(in)) != null)
+ {
+ if (line.startsWith(_footer1) || line.startsWith(_footer2))
+ {
+ break;
+ }
+
+ pemBuf.append(line);
+ }
+
+ if (pemBuf.length() != 0)
+ {
+ try
+ {
+ return ASN1Sequence.getInstance(Base64.decode(pemBuf.toString()));
+ }
+ catch (Exception e)
+ {
+ throw new IOException("malformed PEM data encountered");
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
new file mode 100644
index 000000000..08fd6b0b7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
@@ -0,0 +1,372 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.io.pem.PemObject;
+import org.spongycastle.util.io.pem.PemWriter;
+
+/**
+ * CertPath implementation for X.509 certificates.
+ * <br />
+ **/
+public class PKIXCertPath
+ extends CertPath
+{
+ static final List certPathEncodings;
+
+ static
+ {
+ List encodings = new ArrayList();
+ encodings.add("PkiPath");
+ encodings.add("PEM");
+ encodings.add("PKCS7");
+ certPathEncodings = Collections.unmodifiableList(encodings);
+ }
+
+ private List certificates;
+
+ /**
+ * @param certs
+ */
+ private List sortCerts(
+ List certs)
+ {
+ if (certs.size() < 2)
+ {
+ return certs;
+ }
+
+ X500Principal issuer = ((X509Certificate)certs.get(0)).getIssuerX500Principal();
+ boolean okay = true;
+
+ for (int i = 1; i != certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+
+ if (issuer.equals(cert.getSubjectX500Principal()))
+ {
+ issuer = ((X509Certificate)certs.get(i)).getIssuerX500Principal();
+ }
+ else
+ {
+ okay = false;
+ break;
+ }
+ }
+
+ if (okay)
+ {
+ return certs;
+ }
+
+ // find end-entity cert
+ List retList = new ArrayList(certs.size());
+ List orig = new ArrayList(certs);
+
+ for (int i = 0; i < certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+ boolean found = false;
+
+ X500Principal subject = cert.getSubjectX500Principal();
+
+ for (int j = 0; j != certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (c.getIssuerX500Principal().equals(subject))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ retList.add(cert);
+ certs.remove(i);
+ }
+ }
+
+ // can only have one end entity cert - something's wrong, give up.
+ if (retList.size() > 1)
+ {
+ return orig;
+ }
+
+ for (int i = 0; i != retList.size(); i++)
+ {
+ issuer = ((X509Certificate)retList.get(i)).getIssuerX500Principal();
+
+ for (int j = 0; j < certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (issuer.equals(c.getSubjectX500Principal()))
+ {
+ retList.add(c);
+ certs.remove(j);
+ break;
+ }
+ }
+ }
+
+ // make sure all certificates are accounted for.
+ if (certs.size() > 0)
+ {
+ return orig;
+ }
+
+ return retList;
+ }
+
+ PKIXCertPath(List certificates)
+ {
+ super("X.509");
+ this.certificates = sortCerts(new ArrayList(certificates));
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ **/
+ PKIXCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ super("X.509");
+ try
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Primitive derObject = derInStream.readObject();
+ if (!(derObject instanceof ASN1Sequence))
+ {
+ throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+ }
+ Enumeration e = ((ASN1Sequence)derObject).getObjects();
+ certificates = new ArrayList();
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ while (e.hasMoreElements())
+ {
+ ASN1Encodable element = (ASN1Encodable)e.nextElement();
+ byte[] encoded = element.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ certificates.add(0, certFactory.generateCertificate(
+ new ByteArrayInputStream(encoded)));
+ }
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7") || encoding.equalsIgnoreCase("PEM"))
+ {
+ inStream = new BufferedInputStream(inStream);
+ certificates = new ArrayList();
+ CertificateFactory certFactory= CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ Certificate cert;
+ while ((cert = certFactory.generateCertificate(inStream)) != null)
+ {
+ certificates.add(cert);
+ }
+ }
+ else
+ {
+ throw new CertificateException("unsupported encoding: " + encoding);
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString());
+ }
+ catch (NoSuchProviderException ex)
+ {
+ throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString());
+ }
+
+ this.certificates = sortCerts(certificates);
+ }
+
+ /**
+ * Returns an iteration of the encodings supported by this
+ * certification path, with the default encoding
+ * first. Attempts to modify the returned Iterator via its
+ * remove method result in an UnsupportedOperationException.
+ *
+ * @return an Iterator over the names of the supported encodings (as Strings)
+ **/
+ public Iterator getEncodings()
+ {
+ return certPathEncodings.iterator();
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the default encoding.
+ *
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error occurs
+ **/
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ Iterator iter = getEncodings();
+ if (iter.hasNext())
+ {
+ Object enc = iter.next();
+ if (enc instanceof String)
+ {
+ return getEncoded((String)enc);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the specified encoding.
+ *
+ * @param encoding the name of the encoding to use
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error
+ * occurs or the encoding requested is not supported
+ *
+ **/
+ public byte[] getEncoded(String encoding)
+ throws CertificateEncodingException
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ ListIterator iter = certificates.listIterator(certificates.size());
+ while (iter.hasPrevious())
+ {
+ v.add(toASN1Object((X509Certificate)iter.previous()));
+ }
+
+ return toDEREncoded(new DERSequence(v));
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7"))
+ {
+ ContentInfo encInfo = new ContentInfo(PKCSObjectIdentifiers.data, null);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ v.add(toASN1Object((X509Certificate)certificates.get(i)));
+ }
+
+ SignedData sd = new SignedData(
+ new ASN1Integer(1),
+ new DERSet(),
+ encInfo,
+ new DERSet(v),
+ null,
+ new DERSet());
+
+ return toDEREncoded(new ContentInfo(
+ PKCSObjectIdentifiers.signedData, sd));
+ }
+ else if (encoding.equalsIgnoreCase("PEM"))
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
+
+ try
+ {
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
+ }
+
+ pWrt.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+ }
+
+ return bOut.toByteArray();
+ }
+ else
+ {
+ throw new CertificateEncodingException("unsupported encoding: " + encoding);
+ }
+ }
+
+ /**
+ * Returns the list of certificates in this certification
+ * path. The List returned must be immutable and thread-safe.
+ *
+ * @return an immutable List of Certificates (may be empty, but not null)
+ **/
+ public List getCertificates()
+ {
+ return Collections.unmodifiableList(new ArrayList(certificates));
+ }
+
+ /**
+ * Return a DERObject containing the encoded certificate.
+ *
+ * @param cert the X509Certificate object to be encoded
+ *
+ * @return the DERObject
+ **/
+ private ASN1Primitive toASN1Object(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return new ASN1InputStream(cert.getEncoded()).readObject();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Exception while encoding certificate: " + e.toString());
+ }
+ }
+
+ private byte[] toDEREncoded(ASN1Encodable obj)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException("Exception thrown: " + e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
new file mode 100644
index 000000000..780cad8c1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
@@ -0,0 +1,318 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.X509Extension;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+public class X509CRLEntryObject extends X509CRLEntry
+{
+ private TBSCertList.CRLEntry c;
+
+ private X500Name certificateIssuer;
+ private int hashValue;
+ private boolean isHashValueSet;
+
+ protected X509CRLEntryObject(TBSCertList.CRLEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = null;
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+ * is <code>false</code> {@link #getCertificateIssuer()} will always
+ * return <code>null</code>, <code>previousCertificateIssuer</code> is
+ * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+ * has no certificate issuer CRL entry extension
+ * <code>previousCertificateIssuer</code> is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TBSCertList.CRLEntry object.
+ * @param isIndirect
+ * <code>true</code> if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CRLEntry.
+ */
+ protected X509CRLEntryObject(
+ TBSCertList.CRLEntry c,
+ boolean isIndirect,
+ X500Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+ }
+
+ /**
+ * Will return true if any extensions are present and marked as critical as
+ * we currently don't handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ return extns != null && !extns.isEmpty();
+ }
+
+ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ Extension ext = getExtension(Extension.certificateIssuer);
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.getInstance(ext.getParsedValue()).getNames();
+ for (int i = 0; i < names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ return X500Name.getInstance(names[i].getName());
+ }
+ }
+ return null;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public X500Principal getCertificateIssuer()
+ {
+ if (certificateIssuer == null)
+ {
+ return null;
+ }
+ try
+ {
+ return new X500Principal(certificateIssuer.getEncoded());
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ private Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ Extensions exts = c.getExtensions();
+
+ if (exts != null)
+ {
+ return exts.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extension ext = getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Cache the hashCode value - calculating it with the standard method.
+ * @return calculated hashCode.
+ */
+ public int hashCode()
+ {
+ if (!isHashValueSet)
+ {
+ hashValue = super.hashCode();
+ isHashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (o instanceof X509CRLEntryObject)
+ {
+ X509CRLEntryObject other = (X509CRLEntryObject)o;
+
+ return this.c.equals(other.c);
+ }
+
+ return super.equals(this);
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getUserCertificate().getValue();
+ }
+
+ public Date getRevocationDate()
+ {
+ return c.getRevocationDate().getDate();
+ }
+
+ public boolean hasExtensions()
+ {
+ return c.getExtensions() != null;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl);
+ buf.append(" certificateIssuer: ").append(this.getCertificateIssuer()).append(nl);
+
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+ if (e.hasMoreElements())
+ {
+ buf.append(" crlEntryExtensions:").append(nl);
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(X509Extension.reasonCode))
+ {
+ buf.append(CRLReason.getInstance(ASN1Enumerated.getInstance(dIn.readObject()))).append(nl);
+ }
+ else if (oid.equals(X509Extension.certificateIssuer))
+ {
+ buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
new file mode 100644
index 000000000..d387c440b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
@@ -0,0 +1,627 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLNumber;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.util.encoders.Hex;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+public class X509CRLObject
+ extends X509CRL
+{
+ private CertificateList c;
+ private String sigAlgName;
+ private byte[] sigAlgParams;
+ private boolean isIndirect;
+ private boolean isHashCodeSet = false;
+ private int hashCodeValue;
+
+ static boolean isIndirectCRL(X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+ return idp != null
+ && IssuingDistributionPoint.getInstance(ASN1OctetString.getInstance(idp).getOctets()).isIndirectCRL();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCRLException(
+ "Exception reading IssuingDistributionPoint", e);
+ }
+ }
+
+ protected X509CRLObject(
+ CertificateList c)
+ throws CRLException
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = isIndirectCRL(this);
+ }
+ catch (Exception e)
+ {
+ throw new CRLException("CRL contents invalid: " + e);
+ }
+ }
+
+ /**
+ * Will return true if any extensions are present and marked
+ * as critical as we currently dont handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ if (extns == null)
+ {
+ return false;
+ }
+
+ extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+ return !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ if (this.getVersion() == 2)
+ {
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertList().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ verify(key, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+ {
+ throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+ }
+
+ Signature sig;
+
+ if (sigProvider != null)
+ {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+ else
+ {
+ sig = Signature.getInstance(getSigAlgName());
+ }
+
+ sig.initVerify(key);
+ sig.update(this.getTBSCertList());
+
+ if (!sig.verify(this.getSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public Principal getIssuerDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+ }
+
+ public X500Principal getIssuerX500Principal()
+ {
+ try
+ {
+ return new X500Principal(c.getIssuer().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Date getThisUpdate()
+ {
+ return c.getThisUpdate().getDate();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (c.getNextUpdate() != null)
+ {
+ return c.getNextUpdate().getDate();
+ }
+
+ return null;
+ }
+
+ private Set loadCRLEntries()
+ {
+ Set entrySet = new HashSet();
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = null; // the issuer
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+ X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ entrySet.add(crlEntry);
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return entrySet;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+ {
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = null; // the issuer
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+ if (serialNumber.equals(entry.getUserCertificate().getValue()))
+ {
+ return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getRevokedCertificates()
+ {
+ Set entrySet = loadCRLEntries();
+
+ if (!entrySet.isEmpty())
+ {
+ return Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public byte[] getTBSCertList()
+ throws CRLException
+ {
+ try
+ {
+ return c.getTBSCertList().getEncoded("DER");
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ public String getSigAlgName()
+ {
+ return sigAlgName;
+ }
+
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ {
+ byte[] tmp = new byte[sigAlgParams.length];
+
+ System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" Version: ").append(this.getVersion()).append(
+ nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN())
+ .append(nl);
+ buf.append(" This update: ").append(this.getThisUpdate())
+ .append(nl);
+ buf.append(" Next update: ").append(this.getNextUpdate())
+ .append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName())
+ .append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(
+ new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: ").append(nl);
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(
+ ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.cRLNumber))
+ {
+ buf.append(
+ new CRLNumber(ASN1Integer.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid.equals(Extension.deltaCRLIndicator))
+ {
+ buf.append(
+ "Base CRL: "
+ + new CRLNumber(ASN1Integer.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid
+ .equals(Extension.issuingDistributionPoint))
+ {
+ buf.append(
+ IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid
+ .equals(Extension.cRLDistributionPoints))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.freshestCRL))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(
+ ASN1Dump.dumpAsString(dIn.readObject()))
+ .append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ Set set = getRevokedCertificates();
+ if (set != null)
+ {
+ Iterator it = set.iterator();
+ while (it.hasNext())
+ {
+ buf.append(it.next());
+ buf.append(nl);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!cert.getType().equals("X.509"))
+ {
+ throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+ }
+
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name caName = c.getIssuer();
+
+ if (certs.hasMoreElements())
+ {
+ BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement());
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+
+ if (entry.getUserCertificate().getValue().equals(serial))
+ {
+ X500Name issuer;
+
+ if (cert instanceof X509Certificate)
+ {
+ issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded());
+ }
+ else
+ {
+ try
+ {
+ issuer = org.spongycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new RuntimeException("Cannot process certificate");
+ }
+ }
+
+ if (!caName.equals(issuer))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (this == other)
+ {
+ return true;
+ }
+
+ if (!(other instanceof X509CRL))
+ {
+ return false;
+ }
+
+ if (other instanceof X509CRLObject)
+ {
+ X509CRLObject crlObject = (X509CRLObject)other;
+
+ if (isHashCodeSet)
+ {
+ boolean otherIsHashCodeSet = crlObject.isHashCodeSet;
+ if (otherIsHashCodeSet)
+ {
+ if (crlObject.hashCodeValue != hashCodeValue)
+ {
+ return false;
+ }
+ }
+ }
+
+ return this.c.equals(crlObject.c);
+ }
+
+ return super.equals(other);
+ }
+
+ public int hashCode()
+ {
+ if (!isHashCodeSet)
+ {
+ isHashCodeSet = true;
+ hashCodeValue = super.hashCode();
+ }
+
+ return hashCodeValue;
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
new file mode 100644
index 000000000..7acb7cad4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
@@ -0,0 +1,903 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.misc.NetscapeRevocationURL;
+import org.spongycastle.asn1.misc.VerisignCzagExtension;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.encoders.Hex;
+
+class X509CertificateObject
+ extends X509Certificate
+ implements PKCS12BagAttributeCarrier
+{
+ private org.spongycastle.asn1.x509.Certificate c;
+ private BasicConstraints basicConstraints;
+ private boolean[] keyUsage;
+ private boolean hashValueSet;
+ private int hashValue;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ public X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate c)
+ throws CertificateParsingException
+ {
+ this.c = c;
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.19");
+
+ if (bytes != null)
+ {
+ basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.15");
+ if (bytes != null)
+ {
+ DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+ bytes = bits.getBytes();
+ int length = (bytes.length * 8) - bits.getPadBits();
+
+ keyUsage = new boolean[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+ keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility
+ {
+ throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+ }
+
+ if (date.getTime() < this.getNotBefore().getTime())
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getSerialNumber().getValue();
+ }
+
+ public Principal getIssuerDN()
+ {
+ try
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public X500Principal getIssuerX500Principal()
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(c.getIssuer());
+
+ return new X500Principal(bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Principal getSubjectDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+ }
+
+ public X500Principal getSubjectX500Principal()
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(c.getSubject());
+
+ return new X500Principal(bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Date getNotBefore()
+ {
+ return c.getStartDate().getDate();
+ }
+
+ public Date getNotAfter()
+ {
+ return c.getEndDate().getDate();
+ }
+
+ public byte[] getTBSCertificate()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ /**
+ * return a more "meaningful" representation for the signature algorithm used in
+ * the certficate.
+ */
+ public String getSigAlgName()
+ {
+ Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ if (prov != null)
+ {
+ String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ Provider[] provs = Security.getProviders();
+
+ //
+ // search every provider looking for a real algorithm
+ //
+ for (int i = 0; i != provs.length; i++)
+ {
+ String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ return this.getSigAlgOID();
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getSigAlgParams()
+ {
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ try
+ {
+ return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getIssuerUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getSubjectUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ return keyUsage;
+ }
+
+ public List getExtendedKeyUsage()
+ throws CertificateParsingException
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.37");
+
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension");
+ }
+ }
+
+ return null;
+ }
+
+ public int getBasicConstraints()
+ {
+ if (basicConstraints != null)
+ {
+ if (basicConstraints.isCA())
+ {
+ if (basicConstraints.getPathLenConstraint() == null)
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return basicConstraints.getPathLenConstraint().intValue();
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ public Collection getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+ }
+
+ public Collection getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getExtensionBytes(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+ if (ext != null)
+ {
+ return ext.getExtnValue().getOctets();
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (!ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ if (this.getVersion() == 3)
+ {
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ String oidId = oid.getId();
+
+ if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
+ || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
+ || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
+ || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
+ || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
+ || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
+ || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
+ {
+ continue;
+ }
+
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ try
+ {
+ return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ return null; // should never happen...
+ }
+ }
+
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof Certificate))
+ {
+ return false;
+ }
+
+ Certificate other = (Certificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public synchronized int hashCode()
+ {
+ if (!hashValueSet)
+ {
+ hashValue = calculateHashCode();
+ hashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ private int calculateHashCode()
+ {
+ try
+ {
+ int hashCode = 0;
+ byte[] certData = this.getEncoded();
+ for (int i = 1; i < certData.length; i++)
+ {
+ hashCode += certData[i] * i;
+ }
+ return hashCode;
+ }
+ catch (CertificateEncodingException e)
+ {
+ return 0;
+ }
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" [0] Version: ").append(this.getVersion()).append(nl);
+ buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl);
+ buf.append(" Start Date: ").append(this.getNotBefore()).append(nl);
+ buf.append(" Final Date: ").append(this.getNotAfter()).append(nl);
+ buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl);
+ buf.append(" Public Key: ").append(this.getPublicKey()).append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: \n");
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.basicConstraints))
+ {
+ buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.keyUsage))
+ {
+ buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+ {
+ buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+ {
+ buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+ {
+ buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ //buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public final void verify(
+ PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature;
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ try
+ {
+ signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ signature = Signature.getInstance(sigName);
+ }
+
+ checkSignature(key, signature);
+ }
+
+ public final void verify(
+ PublicKey key,
+ String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+ Signature signature = Signature.getInstance(sigName, sigProvider);
+
+ checkSignature(key, signature);
+ }
+
+ private void checkSignature(
+ PublicKey key,
+ Signature signature)
+ throws CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException
+ {
+ if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+ // TODO This should go after the initVerify?
+ X509SignatureUtil.setSignatureParameters(signature, params);
+
+ signature.initVerify(key);
+
+ signature.update(this.getTBSCertificate());
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new SignatureException("certificate does not verify with supplied key");
+ }
+ }
+
+ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+ {
+ return false;
+ }
+
+ if (id1.getParameters() == null)
+ {
+ if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (id2.getParameters() == null)
+ {
+ if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return id1.getParameters().equals(id2.getParameters());
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return null;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ list.add(Integers.valueOf(genName.getTagNo()));
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getEncoded());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+ final String addr;
+ try
+ {
+ addr = InetAddress.getByAddress(addrBytes).getHostAddress();
+ }
+ catch (UnknownHostException e)
+ {
+ continue;
+ }
+ list.add(addr);
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(Collections.unmodifiableList(list));
+ }
+ if (temp.size() == 0)
+ {
+ return null;
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
new file mode 100644
index 000000000..41824a085
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -0,0 +1,138 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.PSSParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+class X509SignatureUtil
+{
+ private static final ASN1Null derNull = DERNull.INSTANCE;
+
+ static void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !derNull.equals(params))
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+
+ if (signature.getAlgorithm().endsWith("MGF1"))
+ {
+ try
+ {
+ signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1";
+ }
+ if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+ {
+ ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+
+ return getDigestAlgName((DERObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.getAlgorithm().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ DERObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ConfigurableProvider.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ConfigurableProvider.java
new file mode 100644
index 000000000..fa93489f7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ConfigurableProvider.java
@@ -0,0 +1,39 @@
+package org.spongycastle.jcajce.provider.config;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * Implemented by the BC provider. This allows setting of hidden parameters,
+ * such as the ImplicitCA parameters from X.962, if used.
+ */
+public interface ConfigurableProvider
+{
+ /**
+ * Elliptic Curve CA parameters - thread local version
+ */
+ static final String THREAD_LOCAL_EC_IMPLICITLY_CA = "threadLocalEcImplicitlyCa";
+
+ /**
+ * Elliptic Curve CA parameters - thread local version
+ */
+ static final String EC_IMPLICITLY_CA = "ecImplicitlyCa";
+
+ /**
+ * Diffie-Hellman Default Parameters - thread local version
+ */
+ static final String THREAD_LOCAL_DH_DEFAULT_PARAMS = "threadLocalDhDefaultParams";
+
+ /**
+ * Diffie-Hellman Default Parameters - VM wide version
+ */
+ static final String DH_DEFAULT_PARAMS = "DhDefaultParams";
+
+ void setParameter(String parameterName, Object parameter);
+
+ void addAlgorithm(String key, String value);
+
+ boolean hasAlgorithm(String type, String name);
+
+ void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter);
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/PKCS12StoreParameter.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/PKCS12StoreParameter.java
new file mode 100644
index 000000000..c9bbc8391
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/PKCS12StoreParameter.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jcajce.provider.config;
+
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+
+public class PKCS12StoreParameter
+ implements LoadStoreParameter
+{
+ private final OutputStream out;
+ private final ProtectionParameter protectionParameter;
+ private final boolean forDEREncoding;
+
+ public PKCS12StoreParameter(OutputStream out, char[] password)
+ {
+ this(out, password, false);
+ }
+
+ public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter)
+ {
+ this(out, protectionParameter, false);
+ }
+
+ public PKCS12StoreParameter(OutputStream out, char[] password, boolean forDEREncoding)
+ {
+ this(out, new KeyStore.PasswordProtection(password), forDEREncoding);
+ }
+
+ public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter, boolean forDEREncoding)
+ {
+ this.out = out;
+ this.protectionParameter = protectionParameter;
+ this.forDEREncoding = forDEREncoding;
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return out;
+ }
+
+ public ProtectionParameter getProtectionParameter()
+ {
+ return protectionParameter;
+ }
+
+ public boolean isForDEREncoding()
+ {
+ return forDEREncoding;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ProviderConfiguration.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ProviderConfiguration.java
new file mode 100644
index 000000000..edc4c9eaa
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ProviderConfiguration.java
@@ -0,0 +1,12 @@
+package org.spongycastle.jcajce.provider.config;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+public interface ProviderConfiguration
+{
+ ECParameterSpec getEcImplicitlyCa();
+
+ DHParameterSpec getDHDefaultParameters(int keySize);
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ProviderConfigurationPermission.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ProviderConfigurationPermission.java
new file mode 100644
index 000000000..4fb9dcd08
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/config/ProviderConfigurationPermission.java
@@ -0,0 +1,146 @@
+package org.spongycastle.jcajce.provider.config;
+
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.util.StringTokenizer;
+
+import org.spongycastle.util.Strings;
+
+/**
+ * A permission class to define what can be done with the ConfigurableProvider interface.
+ * <p>
+ * Available permissions are "threadLocalEcImplicitlyCa" and "ecImplicitlyCa" which allow the setting
+ * of the thread local and global ecImplicitlyCa parameters respectively.
+ * </p>
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>ProviderConfigurationPermission("SC"); // enable all permissions</li>
+ * <li>ProviderConfigurationPermission("SC", "threadLocalEcImplicitlyCa"); // enable thread local only</li>
+ * <li>ProviderConfigurationPermission("SC", "ecImplicitlyCa"); // enable global setting only</li>
+ * <li>ProviderConfigurationPermission("SC", "threadLocalEcImplicitlyCa, ecImplicitlyCa"); // enable both explicitly</li>
+ * </ul>
+ * <p>
+ * Note: permission checks are only enforced if a security manager is present.
+ * </p>
+ */
+public class ProviderConfigurationPermission
+ extends BasicPermission
+{
+ private static final int THREAD_LOCAL_EC_IMPLICITLY_CA = 0x01;
+ private static final int EC_IMPLICITLY_CA = 0x02;
+ private static final int THREAD_LOCAL_DH_DEFAULT_PARAMS = 0x04;
+ private static final int DH_DEFAULT_PARAMS = 0x08;
+
+ private static final int ALL = THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA | THREAD_LOCAL_DH_DEFAULT_PARAMS | DH_DEFAULT_PARAMS;
+
+ private static final String THREAD_LOCAL_EC_IMPLICITLY_CA_STR = "threadlocalecimplicitlyca";
+ private static final String EC_IMPLICITLY_CA_STR = "ecimplicitlyca";
+ private static final String THREAD_LOCAL_DH_DEFAULT_PARAMS_STR = "threadlocaldhdefaultparams";
+ private static final String DH_DEFAULT_PARAMS_STR = "dhdefaultparams";
+
+ private static final String ALL_STR = "all";
+
+ private final String actions;
+ private final int permissionMask;
+
+ public ProviderConfigurationPermission(String name)
+ {
+ super(name);
+ this.actions = "all";
+ this.permissionMask = ALL;
+ }
+
+ public ProviderConfigurationPermission(String name, String actions)
+ {
+ super(name, actions);
+ this.actions = actions;
+ this.permissionMask = calculateMask(actions);
+ }
+
+ private int calculateMask(
+ String actions)
+ {
+ StringTokenizer tok = new StringTokenizer(Strings.toLowerCase(actions), " ,");
+ int mask = 0;
+
+ while (tok.hasMoreTokens())
+ {
+ String s = tok.nextToken();
+
+ if (s.equals(THREAD_LOCAL_EC_IMPLICITLY_CA_STR))
+ {
+ mask |= THREAD_LOCAL_EC_IMPLICITLY_CA;
+ }
+ else if (s.equals(EC_IMPLICITLY_CA_STR))
+ {
+ mask |= EC_IMPLICITLY_CA;
+ }
+ else if (s.equals(THREAD_LOCAL_DH_DEFAULT_PARAMS_STR))
+ {
+ mask |= THREAD_LOCAL_DH_DEFAULT_PARAMS;
+ }
+ else if (s.equals(DH_DEFAULT_PARAMS_STR))
+ {
+ mask |= DH_DEFAULT_PARAMS;
+ }
+ else if (s.equals(ALL_STR))
+ {
+ mask |= ALL;
+ }
+ }
+
+ if (mask == 0)
+ {
+ throw new IllegalArgumentException("unknown permissions passed to mask");
+ }
+
+ return mask;
+ }
+
+ public String getActions()
+ {
+ return actions;
+ }
+
+ public boolean implies(
+ Permission permission)
+ {
+ if (!(permission instanceof ProviderConfigurationPermission))
+ {
+ return false;
+ }
+
+ if (!this.getName().equals(permission.getName()))
+ {
+ return false;
+ }
+
+ ProviderConfigurationPermission other = (ProviderConfigurationPermission)permission;
+
+ return (this.permissionMask & other.permissionMask) == other.permissionMask;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (obj instanceof ProviderConfigurationPermission)
+ {
+ ProviderConfigurationPermission other = (ProviderConfigurationPermission)obj;
+
+ return this.permissionMask == other.permissionMask && this.getName().equals(other.getName());
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return this.getName().hashCode() + this.permissionMask;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/BCMessageDigest.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/BCMessageDigest.java
new file mode 100644
index 000000000..56fb9f766
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/BCMessageDigest.java
@@ -0,0 +1,47 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import java.security.MessageDigest;
+
+import org.spongycastle.crypto.Digest;
+
+public class BCMessageDigest
+ extends MessageDigest
+{
+ protected Digest digest;
+
+ protected BCMessageDigest(
+ Digest digest)
+ {
+ super(digest.getAlgorithmName());
+
+ this.digest = digest;
+ }
+
+ public void engineReset()
+ {
+ digest.reset();
+ }
+
+ public void engineUpdate(
+ byte input)
+ {
+ digest.update(input);
+ }
+
+ public void engineUpdate(
+ byte[] input,
+ int offset,
+ int len)
+ {
+ digest.update(input, offset, len);
+ }
+
+ public byte[] engineDigest()
+ {
+ byte[] digestBytes = new byte[digest.getDigestSize()];
+
+ digest.doFinal(digestBytes, 0);
+
+ return digestBytes;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/DigestAlgorithmProvider.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/DigestAlgorithmProvider.java
new file mode 100644
index 000000000..ec316d991
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/DigestAlgorithmProvider.java
@@ -0,0 +1,36 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+abstract class DigestAlgorithmProvider
+ extends AlgorithmProvider
+{
+ protected void addHMACAlgorithm(
+ ConfigurableProvider provider,
+ String algorithm,
+ String algorithmClassName,
+ String keyGeneratorClassName)
+ {
+ String mainName = "HMAC" + algorithm;
+
+ provider.addAlgorithm("Mac." + mainName, algorithmClassName);
+ provider.addAlgorithm("Alg.Alias.Mac.HMAC-" + algorithm, mainName);
+ provider.addAlgorithm("Alg.Alias.Mac.HMAC/" + algorithm, mainName);
+ provider.addAlgorithm("KeyGenerator." + mainName, keyGeneratorClassName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.HMAC-" + algorithm, mainName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.HMAC/" + algorithm, mainName);
+ }
+
+ protected void addHMACAlias(
+ ConfigurableProvider provider,
+ String algorithm,
+ ASN1ObjectIdentifier oid)
+ {
+ String mainName = "HMAC" + algorithm;
+
+ provider.addAlgorithm("Alg.Alias.Mac." + oid, mainName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + oid, mainName);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/GOST3411.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/GOST3411.java
new file mode 100644
index 000000000..7a20eb019
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/GOST3411.java
@@ -0,0 +1,94 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+public class GOST3411
+{
+ private GOST3411()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new GOST3411Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new GOST3411Digest((GOST3411Digest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * GOST3411 HMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new GOST3411Digest()));
+ }
+ }
+
+ /**
+ * PBEWithHmacGOST3411
+ */
+ public static class PBEWithMacKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMacKeyFactory()
+ {
+ super("PBEwithHmacGOST3411", null, false, PKCS12, GOST3411, 256, 0);
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACGOST3411", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = GOST3411.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.GOST3411", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.GOST", "GOST3411");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.GOST-3411", "GOST3411");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + CryptoProObjectIdentifiers.gostR3411, "GOST3411");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACGOST3411", PREFIX + "$PBEWithMacKeyFactory");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + CryptoProObjectIdentifiers.gostR3411, "PBEWITHHMACGOST3411");
+
+ addHMACAlgorithm(provider, "GOST3411", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "GOST3411", CryptoProObjectIdentifiers.gostR3411);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD2.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD2.java
new file mode 100644
index 000000000..ceaa460b6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD2.java
@@ -0,0 +1,75 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.MD2Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class MD2
+{
+ private MD2()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new MD2Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new MD2Digest((MD2Digest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * MD2 HMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new MD2Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACMD2", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = MD2.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.MD2", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md2, "MD2");
+
+ addHMACAlgorithm(provider, "MD2", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD4.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD4.java
new file mode 100644
index 000000000..046e163a5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD4.java
@@ -0,0 +1,75 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.MD4Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class MD4
+{
+ private MD4()
+ {
+
+ }
+
+ /**
+ * MD4 HashMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new MD4Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACMD4", 128, new CipherKeyGenerator());
+ }
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new MD4Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new MD4Digest((MD4Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = MD4.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.MD4", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md4, "MD4");
+
+ addHMACAlgorithm(provider, "MD4", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD5.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD5.java
new file mode 100644
index 000000000..7c070856a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/MD5.java
@@ -0,0 +1,77 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.iana.IANAObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class MD5
+{
+ private MD5()
+ {
+
+ }
+
+ /**
+ * MD5 HashMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new MD5Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACMD5", 128, new CipherKeyGenerator());
+ }
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new MD5Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new MD5Digest((MD5Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = MD5.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.MD5", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");
+
+ addHMACAlgorithm(provider, "MD5", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "MD5", IANAObjectIdentifiers.hmacMD5);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD128.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD128.java
new file mode 100644
index 000000000..81b51dc20
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD128.java
@@ -0,0 +1,75 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.RIPEMD128Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class RIPEMD128
+{
+ private RIPEMD128()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new RIPEMD128Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new RIPEMD128Digest((RIPEMD128Digest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * RIPEMD128 HashMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new RIPEMD128Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACRIPEMD128", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = RIPEMD128.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.RIPEMD128", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128");
+
+ addHMACAlgorithm(provider, "RIPEMD128", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD160.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD160.java
new file mode 100644
index 000000000..d4f420fe1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD160.java
@@ -0,0 +1,113 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.iana.IANAObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+public class RIPEMD160
+{
+ private RIPEMD160()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new RIPEMD160Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new RIPEMD160Digest((RIPEMD160Digest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * RIPEMD160 HMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new RIPEMD160Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACRIPEMD160", 160, new CipherKeyGenerator());
+ }
+ }
+
+
+ //
+ // PKCS12 states that the same algorithm should be used
+ // for the key generation as is used in the HMAC, so that
+ // is what we do here.
+ //
+
+ /**
+ * PBEWithHmacRIPEMD160
+ */
+ public static class PBEWithHmac
+ extends BaseMac
+ {
+ public PBEWithHmac()
+ {
+ super(new HMac(new RIPEMD160Digest()), PKCS12, RIPEMD160, 160);
+ }
+ }
+
+ /**
+ * PBEWithHmacRIPEMD160
+ */
+ public static class PBEWithHmacKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithHmacKeyFactory()
+ {
+ super("PBEwithHmacRIPEMD160", null, false, PKCS12, RIPEMD160, 160, 0);
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = RIPEMD160.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.RIPEMD160", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160");
+
+ addHMACAlgorithm(provider, "RIPEMD160", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "RIPEMD160", IANAObjectIdentifiers.hmacRIPEMD160);
+
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACRIPEMD160", PREFIX + "$PBEWithHmacKeyFactory");
+ provider.addAlgorithm("Mac.PBEWITHHMACRIPEMD160", PREFIX + "$PBEWithHmac");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD256.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD256.java
new file mode 100644
index 000000000..d5e86b4ad
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD256.java
@@ -0,0 +1,75 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.RIPEMD256Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class RIPEMD256
+{
+ private RIPEMD256()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new RIPEMD256Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new RIPEMD256Digest((RIPEMD256Digest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * RIPEMD256 HMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new RIPEMD256Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACRIPEMD256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = RIPEMD256.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.RIPEMD256", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256");
+
+ addHMACAlgorithm(provider, "RIPEMD256", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD320.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD320.java
new file mode 100644
index 000000000..ca09b7c2f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/RIPEMD320.java
@@ -0,0 +1,73 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.RIPEMD320Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class RIPEMD320
+{
+ private RIPEMD320()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new RIPEMD320Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new RIPEMD320Digest((RIPEMD320Digest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * RIPEMD320 HMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new RIPEMD320Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACRIPEMD320", 320, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = RIPEMD320.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.RIPEMD320", PREFIX + "$Digest");
+
+ addHMACAlgorithm(provider, "RIPEMD320", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA1.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA1.java
new file mode 100644
index 000000000..b8f76ed40
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA1.java
@@ -0,0 +1,200 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.spongycastle.asn1.iana.IANAObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import org.spongycastle.jcajce.provider.symmetric.util.PBE;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+public class SHA1
+{
+ private SHA1()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA1Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA1Digest((SHA1Digest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * SHA1 HMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA1Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA1", 160, new CipherKeyGenerator());
+ }
+ }
+
+ /**
+ * SHA1 HMac
+ */
+ public static class SHA1Mac
+ extends BaseMac
+ {
+ public SHA1Mac()
+ {
+ super(new HMac(new SHA1Digest()));
+ }
+ }
+
+ /**
+ * PBEWithHmacSHA
+ */
+ public static class PBEWithMacKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMacKeyFactory()
+ {
+ super("PBEwithHmacSHA", null, false, PKCS12, SHA1, 160, 0);
+ }
+ }
+
+
+ public static class BasePBKDF2WithHmacSHA1
+ extends BaseSecretKeyFactory
+ {
+ private int scheme;
+
+ public BasePBKDF2WithHmacSHA1(String name, int scheme)
+ {
+ super(name, PKCSObjectIdentifiers.id_PBKDF2);
+
+ this.scheme = scheme;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ throw new InvalidKeySpecException("missing required salt");
+ }
+
+ if (pbeSpec.getIterationCount() <= 0)
+ {
+ throw new InvalidKeySpecException("positive iteration count required: "
+ + pbeSpec.getIterationCount());
+ }
+
+ if (pbeSpec.getKeyLength() <= 0)
+ {
+ throw new InvalidKeySpecException("positive key length required: "
+ + pbeSpec.getKeyLength());
+ }
+
+ if (pbeSpec.getPassword().length == 0)
+ {
+ throw new IllegalArgumentException("password empty");
+ }
+
+ int digest = SHA1;
+ int keySize = pbeSpec.getKeyLength();
+ int ivSize = -1; // JDK 1,2 and earlier does not understand simplified version.
+ CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ public static class PBKDF2WithHmacSHA1UTF8
+ extends BasePBKDF2WithHmacSHA1
+ {
+ public PBKDF2WithHmacSHA1UTF8()
+ {
+ super("PBKDF2WithHmacSHA1", PKCS5S2_UTF8);
+ }
+ }
+
+ public static class PBKDF2WithHmacSHA18BIT
+ extends BasePBKDF2WithHmacSHA1
+ {
+ public PBKDF2WithHmacSHA18BIT()
+ {
+ super("PBKDF2WithHmacSHA1And8bit", PKCS5S2);
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA1.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-1", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA", "SHA-1");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
+
+ addHMACAlgorithm(provider, "SHA1", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA1", PKCSObjectIdentifiers.id_hmacWithSHA1);
+ addHMACAlias(provider, "SHA1", IANAObjectIdentifiers.hmacSHA1);
+
+ provider.addAlgorithm("Mac.PBEWITHHMACSHA", PREFIX + "$SHA1Mac");
+ provider.addAlgorithm("Mac.PBEWITHHMACSHA1", PREFIX + "$SHA1Mac");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHHMACSHA", "PBEWITHHMACSHA1");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + OIWObjectIdentifiers.idSHA1, "PBEWITHHMACSHA1");
+ provider.addAlgorithm("Alg.Alias.Mac." + OIWObjectIdentifiers.idSHA1, "PBEWITHHMACSHA");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACSHA1", PREFIX + "$PBEWithMacKeyFactory");
+ provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1", PREFIX + "$PBKDF2WithHmacSHA1UTF8");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WithHmacSHA1AndUTF8", "PBKDF2WithHmacSHA1");
+ provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA224.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA224.java
new file mode 100644
index 000000000..3a075eab0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA224.java
@@ -0,0 +1,76 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class SHA224
+{
+ private SHA224()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA224Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA224Digest((SHA224Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA224Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA224", 224, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA224.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-224", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA224", "SHA-224");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224");
+
+ addHMACAlgorithm(provider, "SHA224", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA256.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA256.java
new file mode 100644
index 000000000..f5e092a87
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA256.java
@@ -0,0 +1,96 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+public class SHA256
+{
+ private SHA256()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA256Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA256Digest((SHA256Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA256Digest()));
+ }
+ }
+
+ /**
+ * PBEWithHmacSHA
+ */
+ public static class PBEWithMacKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMacKeyFactory()
+ {
+ super("PBEwithHmacSHA256", null, false, PKCS12, SHA256, 256, 0);
+ }
+ }
+
+ /**
+ * HMACSHA256
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA256.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-256", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACSHA256", PREFIX + "$PBEWithMacKeyFactory");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHHMACSHA-256", "PBEWITHHMACSHA256");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + NISTObjectIdentifiers.id_sha256, "PBEWITHHMACSHA256");
+
+ addHMACAlgorithm(provider, "SHA256", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
+ addHMACAlias(provider, "SHA256", NISTObjectIdentifiers.id_sha256);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA3.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA3.java
new file mode 100644
index 000000000..21eedda78
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA3.java
@@ -0,0 +1,171 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.SHA3Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class SHA3
+{
+ private SHA3()
+ {
+
+ }
+
+ static public class DigestSHA3
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public DigestSHA3(int size)
+ {
+ super(new SHA3Digest(size));
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ BCMessageDigest d = (BCMessageDigest)super.clone();
+ d.digest = new SHA3Digest((SHA3Digest)digest);
+
+ return d;
+ }
+ }
+
+ static public class Digest224
+ extends DigestSHA3
+ {
+ public Digest224()
+ {
+ super(224);
+ }
+ }
+
+ static public class Digest256
+ extends DigestSHA3
+ {
+ public Digest256()
+ {
+ super(256);
+ }
+ }
+
+ static public class Digest384
+ extends DigestSHA3
+ {
+ public Digest384()
+ {
+ super(384);
+ }
+ }
+
+ static public class Digest512
+ extends DigestSHA3
+ {
+ public Digest512()
+ {
+ super(512);
+ }
+ }
+
+ /**
+ * SHA3 HMac
+ */
+ public static class HashMac224
+ extends BaseMac
+ {
+ public HashMac224()
+ {
+ super(new HMac(new SHA3Digest(224)));
+ }
+ }
+
+ public static class HashMac256
+ extends BaseMac
+ {
+ public HashMac256()
+ {
+ super(new HMac(new SHA3Digest(256)));
+ }
+ }
+
+ public static class HashMac384
+ extends BaseMac
+ {
+ public HashMac384()
+ {
+ super(new HMac(new SHA3Digest(384)));
+ }
+ }
+
+ public static class HashMac512
+ extends BaseMac
+ {
+ public HashMac512()
+ {
+ super(new HMac(new SHA3Digest(512)));
+ }
+ }
+
+ public static class KeyGenerator224
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator224()
+ {
+ super("HMACSHA3-224", 224, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGenerator256
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator256()
+ {
+ super("HMACSHA3-256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGenerator384
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator384()
+ {
+ super("HMACSHA3-384", 384, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGenerator512
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator512()
+ {
+ super("HMACSHA3-512", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA3.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA3-224", PREFIX + "$Digest224");
+ provider.addAlgorithm("MessageDigest.SHA3-256", PREFIX + "$Digest256");
+ provider.addAlgorithm("MessageDigest.SHA3-384", PREFIX + "$Digest384");
+ provider.addAlgorithm("MessageDigest.SHA3-512", PREFIX + "$Digest512");
+ // look for an object identifier (NIST???) for SHA3 family
+ // provider.addAlgorithm("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA3, "SHA3-224"); // *****
+
+ addHMACAlgorithm(provider, "SHA3-224", PREFIX + "$HashMac224", PREFIX + "$KeyGenerator224");
+ addHMACAlgorithm(provider, "SHA3-256", PREFIX + "$HashMac256", PREFIX + "$KeyGenerator256");
+ addHMACAlgorithm(provider, "SHA3-384", PREFIX + "$HashMac384", PREFIX + "$KeyGenerator384");
+ addHMACAlgorithm(provider, "SHA3-512", PREFIX + "$HashMac512", PREFIX + "$KeyGenerator512");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA384.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA384.java
new file mode 100644
index 000000000..dc13adb6b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA384.java
@@ -0,0 +1,89 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.crypto.macs.OldHMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class SHA384
+{
+ private SHA384()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA384Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA384Digest((SHA384Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA384Digest()));
+ }
+ }
+
+ /**
+ * HMACSHA384
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA384", 384, new CipherKeyGenerator());
+ }
+ }
+
+ public static class OldSHA384
+ extends BaseMac
+ {
+ public OldSHA384()
+ {
+ super(new OldHMac(new SHA384Digest()));
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA384.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-384", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha384, "SHA-384");
+ provider.addAlgorithm("Mac.OLDHMACSHA384", PREFIX + "$OldSHA384");
+
+ addHMACAlgorithm(provider, "SHA384", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA512.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA512.java
new file mode 100644
index 000000000..3c05b7485
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SHA512.java
@@ -0,0 +1,179 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.digests.SHA512tDigest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.crypto.macs.OldHMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class SHA512
+{
+ private SHA512()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA512Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA512Digest((SHA512Digest)digest);
+
+ return d;
+ }
+ }
+
+ static public class DigestT
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public DigestT(int bitLength)
+ {
+ super(new SHA512tDigest(bitLength));
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ DigestT d = (DigestT)super.clone();
+ d.digest = new SHA512tDigest((SHA512tDigest)digest);
+
+ return d;
+ }
+ }
+
+ static public class DigestT224
+ extends DigestT
+ {
+ public DigestT224()
+ {
+ super(224);
+ }
+ }
+
+ static public class DigestT256
+ extends DigestT
+ {
+ public DigestT256()
+ {
+ super(256);
+ }
+ }
+
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA512Digest()));
+ }
+ }
+
+ public static class HashMacT224
+ extends BaseMac
+ {
+ public HashMacT224()
+ {
+ super(new HMac(new SHA512tDigest(224)));
+ }
+ }
+
+ public static class HashMacT256
+ extends BaseMac
+ {
+ public HashMacT256()
+ {
+ super(new HMac(new SHA512tDigest(256)));
+ }
+ }
+
+ /**
+ * SHA-512 HMac
+ */
+ public static class OldSHA512
+ extends BaseMac
+ {
+ public OldSHA512()
+ {
+ super(new OldHMac(new SHA512Digest()));
+ }
+ }
+
+ /**
+ * HMACSHA512
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA512", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGeneratorT224
+ extends BaseKeyGenerator
+ {
+ public KeyGeneratorT224()
+ {
+ super("HMACSHA512/224", 224, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGeneratorT256
+ extends BaseKeyGenerator
+ {
+ public KeyGeneratorT256()
+ {
+ super("HMACSHA512/256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA512.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-512", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
+
+ provider.addAlgorithm("MessageDigest.SHA-512/224", PREFIX + "$DigestT224");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA512/224", "SHA-512/224");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512_224, "SHA-512/224");
+
+ provider.addAlgorithm("MessageDigest.SHA-512/256", PREFIX + "$DigestT256");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA512256", "SHA-512/256");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512_256, "SHA-512/256");
+
+ provider.addAlgorithm("Mac.OLDHMACSHA512", PREFIX + "$OldSHA512");
+
+ addHMACAlgorithm(provider, "SHA512", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
+
+ addHMACAlgorithm(provider, "SHA512/224", PREFIX + "$HashMacT224", PREFIX + "$KeyGeneratorT224");
+ addHMACAlgorithm(provider, "SHA512/256", PREFIX + "$HashMacT256", PREFIX + "$KeyGeneratorT256");
+ }
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SM3.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SM3.java
new file mode 100644
index 000000000..46a49945a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/SM3.java
@@ -0,0 +1,47 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.crypto.digests.SM3Digest;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+
+public class SM3
+{
+ private SM3()
+ {
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SM3Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SM3Digest((SM3Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SM3.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SM3", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SM3", "SM3");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.1.2.156.197.1.401", "SM3");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Skein.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Skein.java
new file mode 100644
index 000000000..f559bd35b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Skein.java
@@ -0,0 +1,740 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.SkeinDigest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.crypto.macs.SkeinMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class Skein
+{
+ private Skein()
+ {
+ }
+
+ public static class DigestSkein256
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public DigestSkein256(int outputSize)
+ {
+ super(new SkeinDigest(SkeinDigest.SKEIN_256, outputSize));
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ BCMessageDigest d = (BCMessageDigest)super.clone();
+ d.digest = new SkeinDigest((SkeinDigest)digest);
+
+ return d;
+ }
+ }
+
+ public static class Digest_256_128
+ extends DigestSkein256
+ {
+ public Digest_256_128()
+ {
+ super(128);
+ }
+ }
+
+ public static class Digest_256_160
+ extends DigestSkein256
+ {
+ public Digest_256_160()
+ {
+ super(160);
+ }
+ }
+
+ public static class Digest_256_224
+ extends DigestSkein256
+ {
+ public Digest_256_224()
+ {
+ super(224);
+ }
+ }
+
+ public static class Digest_256_256
+ extends DigestSkein256
+ {
+ public Digest_256_256()
+ {
+ super(256);
+ }
+ }
+
+ public static class DigestSkein512
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public DigestSkein512(int outputSize)
+ {
+ super(new SkeinDigest(SkeinDigest.SKEIN_512, outputSize));
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ BCMessageDigest d = (BCMessageDigest)super.clone();
+ d.digest = new SkeinDigest((SkeinDigest)digest);
+
+ return d;
+ }
+ }
+
+ public static class Digest_512_128
+ extends DigestSkein512
+ {
+ public Digest_512_128()
+ {
+ super(128);
+ }
+ }
+
+ public static class Digest_512_160
+ extends DigestSkein512
+ {
+ public Digest_512_160()
+ {
+ super(160);
+ }
+ }
+
+ public static class Digest_512_224
+ extends DigestSkein512
+ {
+ public Digest_512_224()
+ {
+ super(224);
+ }
+ }
+
+ public static class Digest_512_256
+ extends DigestSkein512
+ {
+ public Digest_512_256()
+ {
+ super(256);
+ }
+ }
+
+ public static class Digest_512_384
+ extends DigestSkein512
+ {
+ public Digest_512_384()
+ {
+ super(384);
+ }
+ }
+
+ public static class Digest_512_512
+ extends DigestSkein512
+ {
+ public Digest_512_512()
+ {
+ super(512);
+ }
+ }
+
+ public static class DigestSkein1024
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public DigestSkein1024(int outputSize)
+ {
+ super(new SkeinDigest(SkeinDigest.SKEIN_1024, outputSize));
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ BCMessageDigest d = (BCMessageDigest)super.clone();
+ d.digest = new SkeinDigest((SkeinDigest)digest);
+
+ return d;
+ }
+ }
+
+ public static class Digest_1024_384
+ extends DigestSkein1024
+ {
+ public Digest_1024_384()
+ {
+ super(384);
+ }
+ }
+
+ public static class Digest_1024_512
+ extends DigestSkein1024
+ {
+ public Digest_1024_512()
+ {
+ super(512);
+ }
+ }
+
+ public static class Digest_1024_1024
+ extends DigestSkein1024
+ {
+ public Digest_1024_1024()
+ {
+ super(1024);
+ }
+ }
+
+ /**
+ * Skein HMac
+ */
+ public static class HashMac_256_128
+ extends BaseMac
+ {
+ public HashMac_256_128()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_256, 128)));
+ }
+ }
+
+ public static class HashMac_256_160
+ extends BaseMac
+ {
+ public HashMac_256_160()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_256, 160)));
+ }
+ }
+
+ public static class HashMac_256_224
+ extends BaseMac
+ {
+ public HashMac_256_224()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_256, 224)));
+ }
+ }
+
+ public static class HashMac_256_256
+ extends BaseMac
+ {
+ public HashMac_256_256()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_256, 256)));
+ }
+ }
+
+ public static class HashMac_512_128
+ extends BaseMac
+ {
+ public HashMac_512_128()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_512, 128)));
+ }
+ }
+
+ public static class HashMac_512_160
+ extends BaseMac
+ {
+ public HashMac_512_160()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_512, 160)));
+ }
+ }
+
+ public static class HashMac_512_224
+ extends BaseMac
+ {
+ public HashMac_512_224()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_512, 224)));
+ }
+ }
+
+ public static class HashMac_512_256
+ extends BaseMac
+ {
+ public HashMac_512_256()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_512, 256)));
+ }
+ }
+
+ public static class HashMac_512_384
+ extends BaseMac
+ {
+ public HashMac_512_384()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_512, 384)));
+ }
+ }
+
+ public static class HashMac_512_512
+ extends BaseMac
+ {
+ public HashMac_512_512()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_512, 512)));
+ }
+ }
+
+ public static class HashMac_1024_384
+ extends BaseMac
+ {
+ public HashMac_1024_384()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_1024, 384)));
+ }
+ }
+
+ public static class HashMac_1024_512
+ extends BaseMac
+ {
+ public HashMac_1024_512()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_1024, 512)));
+ }
+ }
+
+ public static class HashMac_1024_1024
+ extends BaseMac
+ {
+ public HashMac_1024_1024()
+ {
+ super(new HMac(new SkeinDigest(SkeinDigest.SKEIN_1024, 1024)));
+ }
+ }
+
+ public static class HMacKeyGenerator_256_128
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_256_128()
+ {
+ super("HMACSkein-256-128", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_256_160
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_256_160()
+ {
+ super("HMACSkein-256-160", 160, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_256_224
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_256_224()
+ {
+ super("HMACSkein-256-224", 224, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_256_256
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_256_256()
+ {
+ super("HMACSkein-256-256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_512_128
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_512_128()
+ {
+ super("HMACSkein-512-128", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_512_160
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_512_160()
+ {
+ super("HMACSkein-512-160", 160, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_512_224
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_512_224()
+ {
+ super("HMACSkein-512-224", 224, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_512_256
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_512_256()
+ {
+ super("HMACSkein-512-256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_512_384
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_512_384()
+ {
+ super("HMACSkein-512-384", 384, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_512_512
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_512_512()
+ {
+ super("HMACSkein-512-512", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_1024_384
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_1024_384()
+ {
+ super("HMACSkein-1024-384", 384, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_1024_512
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_1024_512()
+ {
+ super("HMACSkein-1024-512", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class HMacKeyGenerator_1024_1024
+ extends BaseKeyGenerator
+ {
+ public HMacKeyGenerator_1024_1024()
+ {
+ super("HMACSkein-1024-1024", 1024, new CipherKeyGenerator());
+ }
+ }
+
+ /*
+ * Skein-MAC
+ */
+ public static class SkeinMac_256_128
+ extends BaseMac
+ {
+ public SkeinMac_256_128()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_256, 128));
+ }
+ }
+
+ public static class SkeinMac_256_160
+ extends BaseMac
+ {
+ public SkeinMac_256_160()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_256, 160));
+ }
+ }
+
+ public static class SkeinMac_256_224
+ extends BaseMac
+ {
+ public SkeinMac_256_224()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_256, 224));
+ }
+ }
+
+ public static class SkeinMac_256_256
+ extends BaseMac
+ {
+ public SkeinMac_256_256()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_256, 256));
+ }
+ }
+
+ public static class SkeinMac_512_128
+ extends BaseMac
+ {
+ public SkeinMac_512_128()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_512, 128));
+ }
+ }
+
+ public static class SkeinMac_512_160
+ extends BaseMac
+ {
+ public SkeinMac_512_160()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_512, 160));
+ }
+ }
+
+ public static class SkeinMac_512_224
+ extends BaseMac
+ {
+ public SkeinMac_512_224()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_512, 224));
+ }
+ }
+
+ public static class SkeinMac_512_256
+ extends BaseMac
+ {
+ public SkeinMac_512_256()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_512, 256));
+ }
+ }
+
+ public static class SkeinMac_512_384
+ extends BaseMac
+ {
+ public SkeinMac_512_384()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_512, 384));
+ }
+ }
+
+ public static class SkeinMac_512_512
+ extends BaseMac
+ {
+ public SkeinMac_512_512()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_512, 512));
+ }
+ }
+
+ public static class SkeinMac_1024_384
+ extends BaseMac
+ {
+ public SkeinMac_1024_384()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_1024, 384));
+ }
+ }
+
+ public static class SkeinMac_1024_512
+ extends BaseMac
+ {
+ public SkeinMac_1024_512()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_1024, 512));
+ }
+ }
+
+ public static class SkeinMac_1024_1024
+ extends BaseMac
+ {
+ public SkeinMac_1024_1024()
+ {
+ super(new SkeinMac(SkeinMac.SKEIN_1024, 1024));
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_256_128
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_256_128()
+ {
+ super("Skein-MAC-256-128", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_256_160
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_256_160()
+ {
+ super("Skein-MAC-256-160", 160, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_256_224
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_256_224()
+ {
+ super("Skein-MAC-256-224", 224, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_256_256
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_256_256()
+ {
+ super("Skein-MAC-256-256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_512_128
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_512_128()
+ {
+ super("Skein-MAC-512-128", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_512_160
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_512_160()
+ {
+ super("Skein-MAC-512-160", 160, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_512_224
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_512_224()
+ {
+ super("Skein-MAC-512-224", 224, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_512_256
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_512_256()
+ {
+ super("Skein-MAC-512-256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_512_384
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_512_384()
+ {
+ super("Skein-MAC-512-384", 384, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_512_512
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_512_512()
+ {
+ super("Skein-MAC-512-512", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_1024_384
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_1024_384()
+ {
+ super("Skein-MAC-1024-384", 384, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_1024_512
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_1024_512()
+ {
+ super("Skein-MAC-1024-512", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SkeinMacKeyGenerator_1024_1024
+ extends BaseKeyGenerator
+ {
+ public SkeinMacKeyGenerator_1024_1024()
+ {
+ super("Skein-MAC-1024-1024", 1024, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = Skein.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ // Skein sizes as used in "The Skein Hash Function Family 1.3"
+
+ provider.addAlgorithm("MessageDigest.Skein-256-128", PREFIX + "$Digest_256_128");
+ provider.addAlgorithm("MessageDigest.Skein-256-160", PREFIX + "$Digest_256_160");
+ provider.addAlgorithm("MessageDigest.Skein-256-224", PREFIX + "$Digest_256_224");
+ provider.addAlgorithm("MessageDigest.Skein-256-256", PREFIX + "$Digest_256_256");
+
+ provider.addAlgorithm("MessageDigest.Skein-512-128", PREFIX + "$Digest_512_128");
+ provider.addAlgorithm("MessageDigest.Skein-512-160", PREFIX + "$Digest_512_160");
+ provider.addAlgorithm("MessageDigest.Skein-512-224", PREFIX + "$Digest_512_224");
+ provider.addAlgorithm("MessageDigest.Skein-512-256", PREFIX + "$Digest_512_256");
+ provider.addAlgorithm("MessageDigest.Skein-512-384", PREFIX + "$Digest_512_384");
+ provider.addAlgorithm("MessageDigest.Skein-512-512", PREFIX + "$Digest_512_512");
+
+ provider.addAlgorithm("MessageDigest.Skein-1024-384", PREFIX + "$Digest_1024_384");
+ provider.addAlgorithm("MessageDigest.Skein-1024-512", PREFIX + "$Digest_1024_512");
+ provider.addAlgorithm("MessageDigest.Skein-1024-1024", PREFIX + "$Digest_1024_1024");
+
+ addHMACAlgorithm(provider, "Skein-256-128", PREFIX + "$HashMac_256_128", PREFIX + "$HMacKeyGenerator_256_128");
+ addHMACAlgorithm(provider, "Skein-256-160", PREFIX + "$HashMac_256_160", PREFIX + "$HMacKeyGenerator_256_160");
+ addHMACAlgorithm(provider, "Skein-256-224", PREFIX + "$HashMac_256_224", PREFIX + "$HMacKeyGenerator_256_224");
+ addHMACAlgorithm(provider, "Skein-256-256", PREFIX + "$HashMac_256_256", PREFIX + "$HMacKeyGenerator_256_256");
+
+ addHMACAlgorithm(provider, "Skein-512-128", PREFIX + "$HashMac_512_128", PREFIX + "$HMacKeyGenerator_512_128");
+ addHMACAlgorithm(provider, "Skein-512-160", PREFIX + "$HashMac_512_160", PREFIX + "$HMacKeyGenerator_512_160");
+ addHMACAlgorithm(provider, "Skein-512-224", PREFIX + "$HashMac_512_224", PREFIX + "$HMacKeyGenerator_512_224");
+ addHMACAlgorithm(provider, "Skein-512-256", PREFIX + "$HashMac_512_256", PREFIX + "$HMacKeyGenerator_512_256");
+ addHMACAlgorithm(provider, "Skein-512-384", PREFIX + "$HashMac_512_384", PREFIX + "$HMacKeyGenerator_512_384");
+ addHMACAlgorithm(provider, "Skein-512-512", PREFIX + "$HashMac_512_512", PREFIX + "$HMacKeyGenerator_512_512");
+
+ addHMACAlgorithm(provider, "Skein-1024-384", PREFIX + "$HashMac_1024_384", PREFIX + "$HMacKeyGenerator_1024_384");
+ addHMACAlgorithm(provider, "Skein-1024-512", PREFIX + "$HashMac_1024_512", PREFIX + "$HMacKeyGenerator_1024_512");
+ addHMACAlgorithm(provider, "Skein-1024-1024", PREFIX + "$HashMac_1024_1024", PREFIX + "$HMacKeyGenerator_1024_1024");
+
+ addSkeinMacAlgorithm(provider, 256, 128);
+ addSkeinMacAlgorithm(provider, 256, 160);
+ addSkeinMacAlgorithm(provider, 256, 224);
+ addSkeinMacAlgorithm(provider, 256, 256);
+
+ addSkeinMacAlgorithm(provider, 512, 128);
+ addSkeinMacAlgorithm(provider, 512, 160);
+ addSkeinMacAlgorithm(provider, 512, 224);
+ addSkeinMacAlgorithm(provider, 512, 256);
+ addSkeinMacAlgorithm(provider, 512, 384);
+ addSkeinMacAlgorithm(provider, 512, 512);
+
+ addSkeinMacAlgorithm(provider, 1024, 384);
+ addSkeinMacAlgorithm(provider, 1024, 512);
+ addSkeinMacAlgorithm(provider, 1024, 1024);
+ }
+
+ private void addSkeinMacAlgorithm(ConfigurableProvider provider, int blockSize, int outputSize)
+ {
+ String mainName = "Skein-MAC-" + blockSize + "-" + outputSize;
+ String algorithmClassName = PREFIX + "$SkeinMac_" + blockSize + "_" + outputSize;
+ String keyGeneratorClassName = PREFIX + "$SkeinMacKeyGenerator_" + blockSize + "_" + outputSize;
+
+ provider.addAlgorithm("Mac." + mainName, algorithmClassName);
+ provider.addAlgorithm("Alg.Alias.Mac.Skein-MAC" + blockSize + "/" + outputSize, mainName);
+ provider.addAlgorithm("KeyGenerator." + mainName, keyGeneratorClassName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.Skein-MAC" + blockSize + "/" + outputSize, mainName);
+ }
+
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Tiger.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Tiger.java
new file mode 100644
index 000000000..6bb9b2838
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Tiger.java
@@ -0,0 +1,115 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.asn1.iana.IANAObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.TigerDigest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+public class Tiger
+{
+ private Tiger()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new TigerDigest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new TigerDigest((TigerDigest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * Tiger HMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new TigerDigest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACTIGER", 192, new CipherKeyGenerator());
+ }
+ }
+
+ /**
+ * Tiger HMac
+ */
+ public static class TigerHmac
+ extends BaseMac
+ {
+ public TigerHmac()
+ {
+ super(new HMac(new TigerDigest()));
+ }
+ }
+
+ /**
+ * PBEWithHmacTiger
+ */
+ public static class PBEWithMacKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMacKeyFactory()
+ {
+ super("PBEwithHmacTiger", null, false, PKCS12, TIGER, 192, 0);
+ }
+ }
+
+ /**
+ * PBEWithHmacTiger
+ */
+ public static class PBEWithHashMac
+ extends BaseMac
+ {
+ public PBEWithHashMac()
+ {
+ super(new HMac(new TigerDigest()), PKCS12, TIGER, 192);
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = Tiger.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.TIGER", PREFIX + "$Digest");
+ provider.addAlgorithm("MessageDigest.Tiger", PREFIX + "$Digest"); // JDK 1.1.
+
+ addHMACAlgorithm(provider, "TIGER", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "TIGER", IANAObjectIdentifiers.hmacTIGER);
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHHMACTIGER", PREFIX + "$PBEWithMacKeyFactory");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Whirlpool.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Whirlpool.java
new file mode 100644
index 000000000..e42ddf3f4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/digest/Whirlpool.java
@@ -0,0 +1,73 @@
+package org.spongycastle.jcajce.provider.digest;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.digests.WhirlpoolDigest;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+
+public class Whirlpool
+{
+ private Whirlpool()
+ {
+
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new WhirlpoolDigest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new WhirlpoolDigest((WhirlpoolDigest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * Tiger HMac
+ */
+ public static class HashMac
+ extends BaseMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new WhirlpoolDigest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACWHIRLPOOL", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = Whirlpool.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.WHIRLPOOL", PREFIX + "$Digest");
+
+ addHMACAlgorithm(provider, "WHIRLPOOL", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/BC.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/BC.java
new file mode 100644
index 000000000..ff082c354
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/BC.java
@@ -0,0 +1,27 @@
+package org.spongycastle.jcajce.provider.keystore;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class BC
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.keystore" + ".bc.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyStore.BKS", PREFIX + "BcKeyStoreSpi$Std");
+ provider.addAlgorithm("KeyStore.BKS-V1", PREFIX + "BcKeyStoreSpi$Version1");
+ provider.addAlgorithm("KeyStore.BouncyCastle", PREFIX + "BcKeyStoreSpi$BouncyCastleStore");
+ provider.addAlgorithm("Alg.Alias.KeyStore.UBER", "BouncyCastle");
+ provider.addAlgorithm("Alg.Alias.KeyStore.BOUNCYCASTLE", "BouncyCastle");
+ provider.addAlgorithm("Alg.Alias.KeyStore.spongycastle", "BouncyCastle");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/PKCS12.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/PKCS12.java
new file mode 100644
index 000000000..57f7855cd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/PKCS12.java
@@ -0,0 +1,30 @@
+package org.spongycastle.jcajce.provider.keystore;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class PKCS12
+{
+ private static final String PREFIX = "org.spongycastle.jcajce.provider.keystore" + ".pkcs12.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyStore.PKCS12", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
+ provider.addAlgorithm("KeyStore.BCPKCS12", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
+ provider.addAlgorithm("KeyStore.PKCS12-DEF", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore");
+
+ provider.addAlgorithm("KeyStore.PKCS12-3DES-40RC2", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
+ provider.addAlgorithm("KeyStore.PKCS12-3DES-3DES", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore3DES");
+
+ provider.addAlgorithm("KeyStore.PKCS12-DEF-3DES-40RC2", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore");
+ provider.addAlgorithm("KeyStore.PKCS12-DEF-3DES-3DES", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore3DES");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
new file mode 100644
index 000000000..a06ae3917
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
@@ -0,0 +1,1061 @@
+package org.spongycastle.jcajce.provider.keystore.bc;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+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.KeyFactory;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.spongycastle.crypto.io.DigestInputStream;
+import org.spongycastle.crypto.io.DigestOutputStream;
+import org.spongycastle.crypto.io.MacInputStream;
+import org.spongycastle.crypto.io.MacOutputStream;
+import org.spongycastle.crypto.macs.HMac;
+import org.spongycastle.jce.interfaces.BCKeyStore;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.io.Streams;
+import org.spongycastle.util.io.TeeOutputStream;
+
+public class BcKeyStoreSpi
+ extends KeyStoreSpi
+ implements BCKeyStore
+{
+ private static final int STORE_VERSION = 2;
+
+ private static final int STORE_SALT_SIZE = 20;
+ private static final String STORE_CIPHER = "PBEWithSHAAndTwofish-CBC";
+
+ private static final int KEY_SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private static final String KEY_CIPHER = "PBEWithSHAAnd3-KeyTripleDES-CBC";
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected Hashtable table = new Hashtable();
+
+ protected SecureRandom random = new SecureRandom();
+
+ protected int version;
+
+ public BcKeyStoreSpi(int version)
+ {
+ this.version = version;
+ }
+
+ private class StoreEntry
+ {
+ int type;
+ String alias;
+ Object obj;
+ Certificate[] certChain;
+ Date date = new Date();
+
+ StoreEntry(
+ String alias,
+ Certificate obj)
+ {
+ this.type = CERTIFICATE;
+ this.alias = alias;
+ this.obj = obj;
+ this.certChain = null;
+ }
+
+ StoreEntry(
+ String alias,
+ byte[] obj,
+ Certificate[] certChain)
+ {
+ this.type = SECRET;
+ this.alias = alias;
+ this.obj = obj;
+ this.certChain = certChain;
+ }
+
+ StoreEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] certChain)
+ throws Exception
+ {
+ this.type = SEALED;
+ this.alias = alias;
+ this.certChain = certChain;
+
+ byte[] salt = new byte[KEY_SALT_SIZE];
+
+ random.setSeed(System.currentTimeMillis());
+ random.nextBytes(salt);
+
+ int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DataOutputStream dOut = new DataOutputStream(bOut);
+
+ dOut.writeInt(salt.length);
+ dOut.write(salt);
+ dOut.writeInt(iterationCount);
+
+ Cipher cipher = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+ CipherOutputStream cOut = new CipherOutputStream(dOut, cipher);
+
+ dOut = new DataOutputStream(cOut);
+
+ encodeKey(key, dOut);
+
+ dOut.close();
+
+ obj = bOut.toByteArray();
+ }
+
+ StoreEntry(
+ String alias,
+ Date date,
+ int type,
+ Object obj)
+ {
+ this.alias = alias;
+ this.date = date;
+ this.type = type;
+ this.obj = obj;
+ }
+
+ StoreEntry(
+ String alias,
+ Date date,
+ int type,
+ Object obj,
+ Certificate[] certChain)
+ {
+ this.alias = alias;
+ this.date = date;
+ this.type = type;
+ this.obj = obj;
+ this.certChain = certChain;
+ }
+
+ int getType()
+ {
+ return type;
+ }
+
+ String getAlias()
+ {
+ return alias;
+ }
+
+ Object getObject()
+ {
+ return obj;
+ }
+
+ Object getObject(
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (password == null || password.length == 0)
+ {
+ if (obj instanceof Key)
+ {
+ return obj;
+ }
+ }
+
+ if (type == SEALED)
+ {
+ ByteArrayInputStream bIn = new ByteArrayInputStream((byte[])obj);
+ DataInputStream dIn = new DataInputStream(bIn);
+
+ try
+ {
+ byte[] salt = new byte[dIn.readInt()];
+
+ dIn.readFully(salt);
+
+ int iterationCount = dIn.readInt();
+
+ Cipher cipher = makePBECipher(KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+ CipherInputStream cIn = new CipherInputStream(dIn, cipher);
+
+ try
+ {
+ return decodeKey(new DataInputStream(cIn));
+ }
+ catch (Exception x)
+ {
+ bIn = new ByteArrayInputStream((byte[])obj);
+ dIn = new DataInputStream(bIn);
+
+ salt = new byte[dIn.readInt()];
+
+ dIn.readFully(salt);
+
+ iterationCount = dIn.readInt();
+
+ cipher = makePBECipher("Broken" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+ cIn = new CipherInputStream(dIn, cipher);
+
+ Key k = null;
+
+ try
+ {
+ k = decodeKey(new DataInputStream(cIn));
+ }
+ catch (Exception y)
+ {
+ bIn = new ByteArrayInputStream((byte[])obj);
+ dIn = new DataInputStream(bIn);
+
+ salt = new byte[dIn.readInt()];
+
+ dIn.readFully(salt);
+
+ iterationCount = dIn.readInt();
+
+ cipher = makePBECipher("Old" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+ cIn = new CipherInputStream(dIn, cipher);
+
+ k = decodeKey(new DataInputStream(cIn));
+ }
+
+ //
+ // reencrypt key with correct cipher.
+ //
+ if (k != null)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DataOutputStream dOut = new DataOutputStream(bOut);
+
+ dOut.writeInt(salt.length);
+ dOut.write(salt);
+ dOut.writeInt(iterationCount);
+
+ Cipher out = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+ CipherOutputStream cOut = new CipherOutputStream(dOut, out);
+
+ dOut = new DataOutputStream(cOut);
+
+ encodeKey(k, dOut);
+
+ dOut.close();
+
+ obj = bOut.toByteArray();
+
+ return k;
+ }
+ else
+ {
+ throw new UnrecoverableKeyException("no match");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new UnrecoverableKeyException("no match");
+ }
+ }
+ else
+ {
+ throw new RuntimeException("forget something!");
+ // TODO
+ // if we get to here key was saved as byte data, which
+ // according to the docs means it must be a private key
+ // in EncryptedPrivateKeyInfo (PKCS8 format), later...
+ //
+ }
+ }
+
+ Certificate[] getCertificateChain()
+ {
+ return certChain;
+ }
+
+ Date getDate()
+ {
+ return date;
+ }
+ }
+
+ private void encodeCertificate(
+ Certificate cert,
+ DataOutputStream dOut)
+ throws IOException
+ {
+ try
+ {
+ byte[] cEnc = cert.getEncoded();
+
+ dOut.writeUTF(cert.getType());
+ dOut.writeInt(cEnc.length);
+ dOut.write(cEnc);
+ }
+ catch (CertificateEncodingException ex)
+ {
+ throw new IOException(ex.toString());
+ }
+ }
+
+ private Certificate decodeCertificate(
+ DataInputStream dIn)
+ throws IOException
+ {
+ String type = dIn.readUTF();
+ byte[] cEnc = new byte[dIn.readInt()];
+
+ dIn.readFully(cEnc);
+
+ try
+ {
+ CertificateFactory cFact = CertificateFactory.getInstance(type, BouncyCastleProvider.PROVIDER_NAME);
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cEnc);
+
+ return cFact.generateCertificate(bIn);
+ }
+ catch (NoSuchProviderException ex)
+ {
+ throw new IOException(ex.toString());
+ }
+ catch (CertificateException ex)
+ {
+ throw new IOException(ex.toString());
+ }
+ }
+
+ private void encodeKey(
+ Key key,
+ DataOutputStream dOut)
+ throws IOException
+ {
+ byte[] enc = key.getEncoded();
+
+ if (key instanceof PrivateKey)
+ {
+ dOut.write(KEY_PRIVATE);
+ }
+ else if (key instanceof PublicKey)
+ {
+ dOut.write(KEY_PUBLIC);
+ }
+ else
+ {
+ dOut.write(KEY_SECRET);
+ }
+
+ dOut.writeUTF(key.getFormat());
+ dOut.writeUTF(key.getAlgorithm());
+ dOut.writeInt(enc.length);
+ dOut.write(enc);
+ }
+
+ private Key decodeKey(
+ DataInputStream dIn)
+ throws IOException
+ {
+ int keyType = dIn.read();
+ String format = dIn.readUTF();
+ String algorithm = dIn.readUTF();
+ byte[] enc = new byte[dIn.readInt()];
+ KeySpec spec;
+
+ dIn.readFully(enc);
+
+ if (format.equals("PKCS#8") || format.equals("PKCS8"))
+ {
+ spec = new PKCS8EncodedKeySpec(enc);
+ }
+ else if (format.equals("X.509") || format.equals("X509"))
+ {
+ spec = new X509EncodedKeySpec(enc);
+ }
+ else if (format.equals("RAW"))
+ {
+ return new SecretKeySpec(enc, algorithm);
+ }
+ else
+ {
+ throw new IOException("Key format " + format + " not recognised!");
+ }
+
+ try
+ {
+ switch (keyType)
+ {
+ case KEY_PRIVATE:
+ return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePrivate(spec);
+ case KEY_PUBLIC:
+ return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePublic(spec);
+ case KEY_SECRET:
+ return SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generateSecret(spec);
+ default:
+ throw new IOException("Key type " + keyType + " not recognised!");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Exception creating key: " + e.toString());
+ }
+ }
+
+ protected Cipher makePBECipher(
+ String algorithm,
+ int mode,
+ char[] password,
+ byte[] salt,
+ int iterationCount)
+ throws IOException
+ {
+ try
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
+
+ Cipher cipher = Cipher.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+ cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
+
+ return cipher;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Error initialising store of key store: " + e);
+ }
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ return table.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (table.get(alias) != null);
+ }
+
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Object entry = table.get(alias);
+
+ if (entry == null)
+ {
+ return;
+ }
+
+ table.remove(alias);
+ }
+
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null)
+ {
+ if (entry.getType() == CERTIFICATE)
+ {
+ return (Certificate)entry.getObject();
+ }
+ else
+ {
+ Certificate[] chain = entry.getCertificateChain();
+
+ if (chain != null)
+ {
+ return chain[0];
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration e = table.elements();
+ while (e.hasMoreElements())
+ {
+ StoreEntry entry = (StoreEntry)e.nextElement();
+
+ if (entry.getObject() instanceof Certificate)
+ {
+ Certificate c = (Certificate)entry.getObject();
+
+ if (c.equals(cert))
+ {
+ return entry.getAlias();
+ }
+ }
+ else
+ {
+ Certificate[] chain = entry.getCertificateChain();
+
+ if (chain != null && chain[0].equals(cert))
+ {
+ return entry.getAlias();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null)
+ {
+ return entry.getCertificateChain();
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null)
+ {
+ return entry.getDate();
+ }
+
+ return null;
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry == null || entry.getType() == CERTIFICATE)
+ {
+ return null;
+ }
+
+ return (Key)entry.getObject(password);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null && entry.getType() == CERTIFICATE)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null && entry.getType() != CERTIFICATE)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null && entry.getType() != CERTIFICATE)
+ {
+ throw new KeyStoreException("key store already has a key entry with alias " + alias);
+ }
+
+ table.put(alias, new StoreEntry(alias, cert));
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ table.put(alias, new StoreEntry(alias, key, chain));
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ try
+ {
+ table.put(alias, new StoreEntry(alias, key, password, chain));
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreException(e.toString());
+ }
+ }
+
+ public int engineSize()
+ {
+ return table.size();
+ }
+
+ protected void loadStore(
+ InputStream in)
+ throws IOException
+ {
+ DataInputStream dIn = new DataInputStream(in);
+ int type = dIn.read();
+
+ while (type > NULL)
+ {
+ String alias = dIn.readUTF();
+ Date date = new Date(dIn.readLong());
+ int chainLength = dIn.readInt();
+ Certificate[] chain = null;
+
+ if (chainLength != 0)
+ {
+ chain = new Certificate[chainLength];
+
+ for (int i = 0; i != chainLength; i++)
+ {
+ chain[i] = decodeCertificate(dIn);
+ }
+ }
+
+ switch (type)
+ {
+ case CERTIFICATE:
+ Certificate cert = decodeCertificate(dIn);
+
+ table.put(alias, new StoreEntry(alias, date, CERTIFICATE, cert));
+ break;
+ case KEY:
+ Key key = decodeKey(dIn);
+ table.put(alias, new StoreEntry(alias, date, KEY, key, chain));
+ break;
+ case SECRET:
+ case SEALED:
+ byte[] b = new byte[dIn.readInt()];
+
+ dIn.readFully(b);
+ table.put(alias, new StoreEntry(alias, date, type, b, chain));
+ break;
+ default:
+ throw new RuntimeException("Unknown object type in store.");
+ }
+
+ type = dIn.read();
+ }
+ }
+
+ protected void saveStore(
+ OutputStream out)
+ throws IOException
+ {
+ Enumeration e = table.elements();
+ DataOutputStream dOut = new DataOutputStream(out);
+
+ while (e.hasMoreElements())
+ {
+ StoreEntry entry = (StoreEntry)e.nextElement();
+
+ dOut.write(entry.getType());
+ dOut.writeUTF(entry.getAlias());
+ dOut.writeLong(entry.getDate().getTime());
+
+ Certificate[] chain = entry.getCertificateChain();
+ if (chain == null)
+ {
+ dOut.writeInt(0);
+ }
+ else
+ {
+ dOut.writeInt(chain.length);
+ for (int i = 0; i != chain.length; i++)
+ {
+ encodeCertificate(chain[i], dOut);
+ }
+ }
+
+ switch (entry.getType())
+ {
+ case CERTIFICATE:
+ encodeCertificate((Certificate)entry.getObject(), dOut);
+ break;
+ case KEY:
+ encodeKey((Key)entry.getObject(), dOut);
+ break;
+ case SEALED:
+ case SECRET:
+ byte[] b = (byte[])entry.getObject();
+
+ dOut.writeInt(b.length);
+ dOut.write(b);
+ break;
+ default:
+ throw new RuntimeException("Unknown object type in store.");
+ }
+ }
+
+ dOut.write(NULL);
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ table.clear();
+
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ DataInputStream dIn = new DataInputStream(stream);
+ int version = dIn.readInt();
+
+ if (version != STORE_VERSION)
+ {
+ if (version != 0 && version != 1)
+ {
+ throw new IOException("Wrong version of key store.");
+ }
+ }
+
+ int saltLength = dIn.readInt();
+ if (saltLength <= 0)
+ {
+ throw new IOException("Invalid salt detected");
+ }
+
+ byte[] salt = new byte[saltLength];
+
+ dIn.readFully(salt);
+
+ int iterationCount = dIn.readInt();
+
+ //
+ // we only do an integrity check if the password is provided.
+ //
+ HMac hMac = new HMac(new SHA1Digest());
+ if (password != null && password.length != 0)
+ {
+ byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+
+ PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
+ pbeGen.init(passKey, salt, iterationCount);
+
+ CipherParameters macParams;
+
+ if (version != 2)
+ {
+ macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize());
+ }
+ else
+ {
+ macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8);
+ }
+
+ Arrays.fill(passKey, (byte)0);
+
+ hMac.init(macParams);
+ MacInputStream mIn = new MacInputStream(dIn, hMac);
+
+ loadStore(mIn);
+
+ // Finalise our mac calculation
+ byte[] mac = new byte[hMac.getMacSize()];
+ hMac.doFinal(mac, 0);
+
+ // TODO Should this actually be reading the remainder of the stream?
+ // Read the original mac from the stream
+ byte[] oldMac = new byte[hMac.getMacSize()];
+ dIn.readFully(oldMac);
+
+ if (!Arrays.constantTimeAreEqual(mac, oldMac))
+ {
+ table.clear();
+ throw new IOException("KeyStore integrity check failed.");
+ }
+ }
+ else
+ {
+ loadStore(dIn);
+
+ // TODO Should this actually be reading the remainder of the stream?
+ // Parse the original mac from the stream too
+ byte[] oldMac = new byte[hMac.getMacSize()];
+ dIn.readFully(oldMac);
+ }
+ }
+
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ DataOutputStream dOut = new DataOutputStream(stream);
+ byte[] salt = new byte[STORE_SALT_SIZE];
+ int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+ random.nextBytes(salt);
+
+ dOut.writeInt(version);
+ dOut.writeInt(salt.length);
+ dOut.write(salt);
+ dOut.writeInt(iterationCount);
+
+ HMac hMac = new HMac(new SHA1Digest());
+ MacOutputStream mOut = new MacOutputStream(hMac);
+ PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
+ byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+
+ pbeGen.init(passKey, salt, iterationCount);
+
+ if (version < 2)
+ {
+ hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize()));
+ }
+ else
+ {
+ hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8));
+ }
+
+ for (int i = 0; i != passKey.length; i++)
+ {
+ passKey[i] = 0;
+ }
+
+ saveStore(new TeeOutputStream(dOut, mOut));
+
+ byte[] mac = new byte[hMac.getMacSize()];
+
+ hMac.doFinal(mac, 0);
+
+ dOut.write(mac);
+
+ dOut.close();
+ }
+
+ /**
+ * the BouncyCastle store. This wont work with the key tool as the
+ * store is stored encrypted on disk, so the password is mandatory,
+ * however if you hard drive is in a bad part of town and you absolutely,
+ * positively, don't want nobody peeking at your things, this is the
+ * one to use, no problem! After all in a Bouncy Castle nothing can
+ * touch you.
+ *
+ * Also referred to by the alias UBER.
+ */
+ public static class BouncyCastleStore
+ extends BcKeyStoreSpi
+ {
+ public BouncyCastleStore()
+ {
+ super(1);
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ table.clear();
+
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ DataInputStream dIn = new DataInputStream(stream);
+ int version = dIn.readInt();
+
+ if (version != STORE_VERSION)
+ {
+ if (version != 0 && version != 1)
+ {
+ throw new IOException("Wrong version of key store.");
+ }
+ }
+
+ byte[] salt = new byte[dIn.readInt()];
+
+ if (salt.length != STORE_SALT_SIZE)
+ {
+ throw new IOException("Key store corrupted.");
+ }
+
+ dIn.readFully(salt);
+
+ int iterationCount = dIn.readInt();
+
+ if ((iterationCount < 0) || (iterationCount > 4 * MIN_ITERATIONS))
+ {
+ throw new IOException("Key store corrupted.");
+ }
+
+ String cipherAlg;
+ if (version == 0)
+ {
+ cipherAlg = "Old" + STORE_CIPHER;
+ }
+ else
+ {
+ cipherAlg = STORE_CIPHER;
+ }
+
+ Cipher cipher = this.makePBECipher(cipherAlg, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+ CipherInputStream cIn = new CipherInputStream(dIn, cipher);
+
+ Digest dig = new SHA1Digest();
+ DigestInputStream dgIn = new DigestInputStream(cIn, dig);
+
+ this.loadStore(dgIn);
+
+ // Finalise our digest calculation
+ byte[] hash = new byte[dig.getDigestSize()];
+ dig.doFinal(hash, 0);
+
+ // TODO Should this actually be reading the remainder of the stream?
+ // Read the original digest from the stream
+ byte[] oldHash = new byte[dig.getDigestSize()];
+ Streams.readFully(cIn, oldHash);
+
+ if (!Arrays.constantTimeAreEqual(hash, oldHash))
+ {
+ table.clear();
+ throw new IOException("KeyStore integrity check failed.");
+ }
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ Cipher cipher;
+ DataOutputStream dOut = new DataOutputStream(stream);
+ byte[] salt = new byte[STORE_SALT_SIZE];
+ int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+ random.nextBytes(salt);
+
+ dOut.writeInt(version);
+ dOut.writeInt(salt.length);
+ dOut.write(salt);
+ dOut.writeInt(iterationCount);
+
+ cipher = this.makePBECipher(STORE_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+
+ CipherOutputStream cOut = new CipherOutputStream(dOut, cipher);
+ DigestOutputStream dgOut = new DigestOutputStream(new SHA1Digest());
+
+ this.saveStore(new TeeOutputStream(cOut, dgOut));
+
+ byte[] dig = dgOut.getDigest();
+
+ cOut.write(dig);
+
+ cOut.close();
+ }
+ }
+
+ public static class Std
+ extends BcKeyStoreSpi
+ {
+ public Std()
+ {
+ super(STORE_VERSION);
+ }
+ }
+
+ public static class Version1
+ extends BcKeyStoreSpi
+ {
+ public Version1()
+ {
+ super(1);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
new file mode 100644
index 000000000..115a00012
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -0,0 +1,1778 @@
+package org.spongycastle.jcajce.provider.keystore.pkcs12;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.BEROutputStream;
+import org.spongycastle.asn1.DERBMPString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.GOST28147Parameters;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.AuthenticatedSafe;
+import org.spongycastle.asn1.pkcs.CertBag;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.EncryptedData;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PBES2Parameters;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.config.PKCS12StoreParameter;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.spec.GOST28147ParameterSpec;
+import org.spongycastle.jcajce.spec.PBKDF2KeySpec;
+import org.spongycastle.jce.interfaces.BCKeyStore;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.provider.JDKPKCS12StoreParameter;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.encoders.Hex;
+
+public class PKCS12KeyStoreSpi
+ extends KeyStoreSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+ private static final int SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private static final Provider bcProvider = new BouncyCastleProvider();
+ private static final DefaultSecretKeyProvider keySizeProvider = new DefaultSecretKeyProvider();
+
+ private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private Hashtable localIds = new Hashtable();
+ private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private Hashtable chainCerts = new Hashtable();
+ private Hashtable keyCerts = new Hashtable();
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected SecureRandom random = new SecureRandom();
+
+ // use of final causes problems with JDK 1.2 compiler
+ private CertificateFactory certFact;
+ private ASN1ObjectIdentifier keyAlgorithm;
+ private ASN1ObjectIdentifier certAlgorithm;
+
+ private class CertId
+ {
+ byte[] id;
+
+ CertId(
+ PublicKey key)
+ {
+ this.id = createSubjectKeyId(key).getKeyIdentifier();
+ }
+
+ CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(id);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof CertId))
+ {
+ return false;
+ }
+
+ CertId cId = (CertId)o;
+
+ return Arrays.areEqual(id, cId.id);
+ }
+ }
+
+ public PKCS12KeyStoreSpi(
+ Provider provider,
+ ASN1ObjectIdentifier keyAlgorithm,
+ ASN1ObjectIdentifier certAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+
+ try
+ {
+ if (provider != null)
+ {
+ certFact = CertificateFactory.getInstance("X.509", provider);
+ }
+ else
+ {
+ certFact = CertificateFactory.getInstance("X.509");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+ }
+ }
+
+ private SubjectKeyIdentifier createSubjectKeyId(
+ PublicKey pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)ASN1Primitive.fromByteArray(pubKey.getEncoded()));
+
+ return new SubjectKeyIdentifier(info);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error creating key");
+ }
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (certs.get(alias) != null || keys.get(alias) != null);
+ }
+
+ /**
+ * this is not quite complete - we should follow up on the chain, a bit
+ * tricky if a certificate appears in more than one chain...
+ */
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Key k = (Key)keys.remove(alias);
+
+ Certificate c = (Certificate)certs.remove(alias);
+
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+
+ if (k != null)
+ {
+ String id = (String)localIds.remove(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.remove(id);
+ }
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+ }
+ }
+
+ /**
+ * simply return the cert for the private key
+ */
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificate.");
+ }
+
+ Certificate c = (Certificate)certs.get(alias);
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ String id = (String)localIds.get(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.get(id);
+ }
+ else
+ {
+ c = (Certificate)keyCerts.get(alias);
+ }
+ }
+
+ return c;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration c = certs.elements();
+ Enumeration k = certs.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ c = keyCerts.elements();
+ k = keyCerts.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+ }
+
+ if (!engineIsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ Certificate c = engineGetCertificate(alias);
+
+ if (c != null)
+ {
+ Vector cs = new Vector();
+
+ while (c != null)
+ {
+ X509Certificate x509c = (X509Certificate)c;
+ Certificate nextC = null;
+
+ byte[] bytes = x509c.getExtensionValue(Extension.authorityKeyIdentifier.getId());
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(bytes);
+
+ byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+ aIn = new ASN1InputStream(authBytes);
+
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject());
+ if (id.getKeyIdentifier() != null)
+ {
+ nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+ }
+
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ Principal i = x509c.getIssuerDN();
+ Principal s = x509c.getSubjectDN();
+
+ if (!i.equals(s))
+ {
+ Enumeration e = chainCerts.keys();
+
+ while (e.hasMoreElements())
+ {
+ X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+ Principal sub = crt.getSubjectDN();
+ if (sub.equals(i))
+ {
+ try
+ {
+ x509c.verify(crt.getPublicKey());
+ nextC = crt;
+ break;
+ }
+ catch (Exception ex)
+ {
+ // continue
+ }
+ }
+ }
+ }
+ }
+
+ cs.addElement(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ Certificate[] certChain = new Certificate[cs.size()];
+
+ for (int i = 0; i != certChain.length; i++)
+ {
+ certChain[i] = (Certificate)cs.elementAt(i);
+ }
+
+ return certChain;
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ if (alias == null)
+ {
+ throw new NullPointerException("alias == null");
+ }
+ if (keys.get(alias) == null && certs.get(alias) == null)
+ {
+ return null;
+ }
+ return new Date();
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getKey.");
+ }
+
+ return (Key)keys.get(alias);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ return (certs.get(alias) != null && keys.get(alias) == null);
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ return (keys.get(alias) != null);
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ if (keys.get(alias) != null)
+ {
+ throw new KeyStoreException("There is a key entry with the name " + alias + ".");
+ }
+
+ certs.put(alias, cert);
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ throw new RuntimeException("operation not supported");
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ if (!(key instanceof PrivateKey))
+ {
+ throw new KeyStoreException("PKCS12 does not support non-PrivateKeys");
+ }
+
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ if (keys.get(alias) != null)
+ {
+ engineDeleteEntry(alias);
+ }
+
+ keys.put(alias, key);
+ if (chain != null)
+ {
+ certs.put(alias, chain[0]);
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+ }
+ }
+ }
+
+ public int engineSize()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.size();
+ }
+
+ protected PrivateKey unwrapKey(
+ AlgorithmIdentifier algId,
+ byte[] data,
+ char[] password,
+ boolean wrongPKCS12Zero)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+ try
+ {
+ if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+ {
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PrivateKey out;
+
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ SecretKey k = keyFact.generateSecret(pbeSpec);
+
+ ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+ {
+
+ Cipher cipher = createCipher(Cipher.UNWRAP_MODE, password, algId);
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception unwrapping private key - " + e.toString());
+ }
+
+ throw new IOException("exception unwrapping private key - cannot recognise: " + algorithm);
+ }
+
+ protected byte[] wrapKey(
+ String algorithm,
+ Key key,
+ PKCS12PBEParams pbeParams,
+ char[] password)
+ throws IOException
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ byte[] out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+ out = cipher.wrap(key);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception encrypting data - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] cryptData(
+ boolean forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ boolean wrongPKCS12Zero,
+ byte[] data)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+
+ if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+ {
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+ BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+
+ key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider);
+ int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+ cipher.init(mode, key, defParams);
+ return cipher.doFinal(data);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decrypting data - " + e.toString());
+ }
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+ {
+ try
+ {
+ Cipher cipher = createCipher(Cipher.DECRYPT_MODE, password, algId);
+
+ return cipher.doFinal(data);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decrypting data - " + e.toString());
+ }
+ }
+ else
+ {
+ throw new IOException("unknown PBE algorithm: " + algorithm);
+ }
+ }
+
+ private Cipher createCipher(int mode, char[] password, AlgorithmIdentifier algId)
+ throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
+ PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
+ AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
+
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider);
+ SecretKey key;
+
+ if (func.isDefaultPrf())
+ {
+ key = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme)));
+ }
+ else
+ {
+ key = keyFact.generateSecret(new PBKDF2KeySpec(password, func.getSalt(), func.getIterationCount().intValue(), keySizeProvider.getKeySize(encScheme), func.getPrf()));
+ }
+
+ Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId());
+
+ AlgorithmIdentifier encryptionAlg = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
+
+ ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
+ if (encParams instanceof ASN1OctetString)
+ {
+ cipher.init(mode, key, new IvParameterSpec(ASN1OctetString.getInstance(encParams).getOctets()));
+ }
+ else
+ {
+ // TODO: at the moment it's just GOST, but...
+ GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams);
+
+ cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
+ }
+ return cipher;
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+ bufIn.mark(10);
+
+ int head = bufIn.read();
+
+ if (head != 0x30)
+ {
+ throw new IOException("stream does not represent a PKCS12 key store");
+ }
+
+ bufIn.reset();
+
+ ASN1InputStream bIn = new ASN1InputStream(bufIn);
+ ASN1Sequence obj = (ASN1Sequence)bIn.readObject();
+ Pfx bag = Pfx.getInstance(obj);
+ ContentInfo info = bag.getAuthSafe();
+ Vector chain = new Vector();
+ boolean unmarkedKey = false;
+ boolean wrongPKCS12Zero = false;
+
+ if (bag.getMacData() != null) // check the mac code
+ {
+ MacData mData = bag.getMacData();
+ DigestInfo dInfo = mData.getMac();
+ AlgorithmIdentifier algId = dInfo.getAlgorithmId();
+ byte[] salt = mData.getSalt();
+ int itCount = mData.getIterationCount().intValue();
+
+ byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
+
+ try
+ {
+ byte[] res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, false, data);
+ byte[] dig = dInfo.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ if (password.length > 0)
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ // Try with incorrect zero length password
+ res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, true, data);
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ wrongPKCS12Zero = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+ }
+
+ keys = new IgnoresCaseHashtable();
+ localIds = new Hashtable();
+
+ if (info.getContentType().equals(data))
+ {
+ bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+ AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
+ ContentInfo[] c = authSafe.getContentInfo();
+
+ for (int i = 0; i != c.length; i++)
+ {
+ if (c[i].getContentType().equals(data))
+ {
+ ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+ if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ unmarkedKey = true;
+ keys.put("unmarked", privKey);
+ }
+ }
+ else if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else
+ {
+ System.out.println("extra in data " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else if (c[i].getContentType().equals(encryptedData))
+ {
+ EncryptedData d = EncryptedData.getInstance(c[i].getContent());
+ byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
+ password, wrongPKCS12Zero, d.getContent().getOctets());
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(octets);
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+ if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else if (b.getBagId().equals(keyBag))
+ {
+ org.spongycastle.asn1.pkcs.PrivateKeyInfo kInfo = org.spongycastle.asn1.pkcs.PrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ System.out.println("extra in encryptedData " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else
+ {
+ System.out.println("extra " + c[i].getContentType().getId());
+ System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+ }
+ }
+ }
+
+ certs = new IgnoresCaseHashtable();
+ chainCerts = new Hashtable();
+ keyCerts = new Hashtable();
+
+ for (int i = 0; i != chain.size(); i++)
+ {
+ SafeBag b = (SafeBag)chain.elementAt(i);
+ CertBag cb = CertBag.getInstance(b.getBagValue());
+
+ if (!cb.getCertId().equals(x509Certificate))
+ {
+ throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
+ }
+
+ Certificate cert;
+
+ try
+ {
+ ByteArrayInputStream cIn = new ByteArrayInputStream(
+ ((ASN1OctetString)cb.getCertValue()).getOctets());
+ cert = certFact.generateCertificate(cIn);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+
+ //
+ // set the attributes
+ //
+ ASN1OctetString localId = null;
+ String alias = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Primitive attr = (ASN1Primitive)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
+ PKCS12BagAttributeCarrier bagAttr = null;
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(oid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(oid, attr);
+ }
+ }
+
+ if (oid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ }
+ else if (oid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+ if (unmarkedKey)
+ {
+ if (keyCerts.isEmpty())
+ {
+ String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+
+ keyCerts.put(name, cert);
+ keys.put(name, keys.remove("unmarked"));
+ }
+ }
+ else
+ {
+ //
+ // the local key id needs to override the friendly name
+ //
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ keyCerts.put(name, cert);
+ }
+ if (alias != null)
+ {
+ certs.put(alias, cert);
+ }
+ }
+ }
+ }
+
+ public void engineStore(LoadStoreParameter param)
+ throws IOException,
+ NoSuchAlgorithmException, CertificateException
+ {
+ if (param == null)
+ {
+ throw new IllegalArgumentException("'param' arg cannot be null");
+ }
+
+ if (!(param instanceof PKCS12StoreParameter || param instanceof JDKPKCS12StoreParameter))
+ {
+ throw new IllegalArgumentException(
+ "No support for 'param' of type " + param.getClass().getName());
+ }
+
+ PKCS12StoreParameter bcParam;
+
+ if (param instanceof PKCS12StoreParameter)
+ {
+ bcParam = (PKCS12StoreParameter)param;
+ }
+ else
+ {
+ bcParam = new PKCS12StoreParameter(((JDKPKCS12StoreParameter)param).getOutputStream(),
+ param.getProtectionParameter(), ((JDKPKCS12StoreParameter)param).isUseDEREncoding());
+ }
+
+ char[] password;
+ ProtectionParameter protParam = param.getProtectionParameter();
+ if (protParam == null)
+ {
+ password = null;
+ }
+ else if (protParam instanceof KeyStore.PasswordProtection)
+ {
+ password = ((KeyStore.PasswordProtection)protParam).getPassword();
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "No support for protection parameter of type " + protParam.getClass().getName());
+ }
+
+ doStore(bcParam.getOutputStream(), password, bcParam.isForDEREncoding());
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ doStore(stream, password, false);
+ }
+
+ private void doStore(OutputStream stream, char[] password, boolean useDEREncoding)
+ throws IOException
+ {
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ //
+ // handle the key
+ //
+ ASN1EncodableVector keyS = new ASN1EncodableVector();
+
+
+ Enumeration ks = keys.keys();
+
+ while (ks.hasMoreElements())
+ {
+ byte[] kSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(kSalt);
+
+ String name = (String)ks.nextElement();
+ PrivateKey privKey = (PrivateKey)keys.get(name);
+ PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+ byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+ AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+ boolean attrSet = false;
+ ASN1EncodableVector kName = new ASN1EncodableVector();
+
+ if (privKey instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ Certificate ct = engineGetCertificate(name);
+
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+
+ kSeq.add(oid);
+ kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+ attrSet = true;
+
+ kName.add(new DERSequence(kSeq));
+ }
+ }
+
+ if (!attrSet)
+ {
+ //
+ // set a default friendly name (from the key id) and local id
+ //
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+ Certificate ct = engineGetCertificate(name);
+
+ kSeq.add(pkcs_9_at_localKeyId);
+ kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+ kName.add(new DERSequence(kSeq));
+
+ kSeq = new ASN1EncodableVector();
+
+ kSeq.add(pkcs_9_at_friendlyName);
+ kSeq.add(new DERSet(new DERBMPString(name)));
+
+ kName.add(new DERSequence(kSeq));
+ }
+
+ SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
+ keyS.add(kBag);
+ }
+
+ byte[] keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
+ BEROctetString keyString = new BEROctetString(keySEncoded);
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(cSalt);
+
+ ASN1EncodableVector certSeq = new ASN1EncodableVector();
+ PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+ Hashtable doneCerts = new Hashtable();
+
+ Enumeration cs = keys.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String name = (String)cs.nextElement();
+ Certificate cert = engineGetCertificate(name);
+ boolean cAttrSet = false;
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_localKeyId);
+ fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+ fName.add(new DERSequence(fSeq));
+
+ fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(name)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = certs.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String certId = (String)cs.nextElement();
+ Certificate cert = (Certificate)certs.get(certId);
+ boolean cAttrSet = false;
+
+ if (keys.get(certId) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(certId))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(certId)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = chainCerts.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ CertId certId = (CertId)cs.nextElement();
+ Certificate cert = (Certificate)chainCerts.get(certId);
+
+ if (doneCerts.get(cert) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+ }
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
+ byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
+ EncryptedData cInfo = new EncryptedData(data, cAlgId, new BEROctetString(certBytes));
+
+ ContentInfo[] info = new ContentInfo[]
+ {
+ new ContentInfo(data, keyString),
+ new ContentInfo(encryptedData, cInfo.toASN1Primitive())
+ };
+
+ AuthenticatedSafe auth = new AuthenticatedSafe(info);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream asn1Out;
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(bOut);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(bOut);
+ }
+
+ asn1Out.writeObject(auth);
+
+ byte[] pkg = bOut.toByteArray();
+
+ ContentInfo mainInfo = new ContentInfo(data, new BEROctetString(pkg));
+
+ //
+ // create the mac
+ //
+ byte[] mSalt = new byte[20];
+ int itCount = MIN_ITERATIONS;
+
+ random.nextBytes(mSalt);
+
+ byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+ MacData mData;
+
+ try
+ {
+ byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, DERNull.INSTANCE);
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mSalt, itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(stream);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(stream);
+ }
+
+ asn1Out.writeObject(pfx);
+ }
+
+ private static byte[] calculatePbeMac(
+ ASN1ObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ boolean wrongPkcs12Zero,
+ byte[] data)
+ throws Exception
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+ key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
+
+ Mac mac = Mac.getInstance(oid.getId(), bcProvider);
+ mac.init(key, defParams);
+ mac.update(data);
+ return mac.doFinal();
+ }
+
+ public static class BCPKCS12KeyStore
+ extends PKCS12KeyStoreSpi
+ {
+ public BCPKCS12KeyStore()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class BCPKCS12KeyStore3DES
+ extends PKCS12KeyStoreSpi
+ {
+ public BCPKCS12KeyStore3DES()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore
+ extends PKCS12KeyStoreSpi
+ {
+ public DefPKCS12KeyStore()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore3DES
+ extends PKCS12KeyStoreSpi
+ {
+ public DefPKCS12KeyStore3DES()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ private static class IgnoresCaseHashtable
+ {
+ private Hashtable orig = new Hashtable();
+ private Hashtable keys = new Hashtable();
+
+ public void put(String key, Object value)
+ {
+ String lower = (key == null) ? null : Strings.toLowerCase(key);
+ String k = (String)keys.get(lower);
+ if (k != null)
+ {
+ orig.remove(k);
+ }
+
+ keys.put(lower, key);
+ orig.put(key, value);
+ }
+
+ public Enumeration keys()
+ {
+ return orig.keys();
+ }
+
+ public Object remove(String alias)
+ {
+ String k = (String)keys.remove(alias == null ? null : Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.remove(k);
+ }
+
+ public Object get(String alias)
+ {
+ String k = (String)keys.get(alias == null ? null : Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.get(k);
+ }
+
+ public Enumeration elements()
+ {
+ return orig.elements();
+ }
+ }
+
+ private static class DefaultSecretKeyProvider
+ {
+ private final Map KEY_SIZES;
+
+ DefaultSecretKeyProvider()
+ {
+ Map keySizes = new HashMap();
+
+ keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128));
+
+ keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
+
+ keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
+ keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
+ keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256));
+
+ keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128));
+ keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
+ keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
+
+ keySizes.put(CryptoProObjectIdentifiers.gostR28147_gcfb, Integers.valueOf(256));
+
+ KEY_SIZES = Collections.unmodifiableMap(keySizes);
+ }
+
+ public int getKeySize(AlgorithmIdentifier algorithmIdentifier)
+ {
+ // TODO: not all ciphers/oid relationships are this simple.
+ Integer keySize = (Integer)KEY_SIZES.get(algorithmIdentifier.getAlgorithm());
+
+ if (keySize != null)
+ {
+ return keySize.intValue();
+ }
+
+ return -1;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/AES.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/AES.java
new file mode 100644
index 000000000..21a14482e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/AES.java
@@ -0,0 +1,640 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.asn1.bc.BCObjectIdentifiers;
+import org.spongycastle.asn1.cms.GCMParameters;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.AESFastEngine;
+import org.spongycastle.crypto.engines.AESWrapEngine;
+import org.spongycastle.crypto.engines.RFC3211WrapEngine;
+import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
+import org.spongycastle.crypto.macs.CMac;
+import org.spongycastle.crypto.macs.GMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.CFBBlockCipher;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.crypto.modes.OFBBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Integers;
+
+public final class AES
+{
+ private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
+
+ private AES()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new AESFastEngine();
+ }
+ });
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new AESFastEngine()), 128);
+ }
+ }
+
+ static public class CFB
+ extends BaseBlockCipher
+ {
+ public CFB()
+ {
+ super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128);
+ }
+ }
+
+ static public class OFB
+ extends BaseBlockCipher
+ {
+ public OFB()
+ {
+ super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
+ }
+ }
+
+ static public class GCM
+ extends BaseBlockCipher
+ {
+ public GCM()
+ {
+ super(new GCMBlockCipher(new AESFastEngine()));
+ }
+ }
+
+ public static class AESCMAC
+ extends BaseMac
+ {
+ public AESCMAC()
+ {
+ super(new CMac(new AESFastEngine()));
+ }
+ }
+
+ public static class AESGMAC
+ extends BaseMac
+ {
+ public AESGMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new AESFastEngine())));
+ }
+ }
+
+ public static class Poly1305
+ extends BaseMac
+ {
+ public Poly1305()
+ {
+ super(new org.spongycastle.crypto.macs.Poly1305(new AESFastEngine()));
+ }
+ }
+
+ public static class Poly1305KeyGen
+ extends BaseKeyGenerator
+ {
+ public Poly1305KeyGen()
+ {
+ super("Poly1305-AES", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ static public class Wrap
+ extends BaseWrapCipher
+ {
+ public Wrap()
+ {
+ super(new AESWrapEngine());
+ }
+ }
+
+ public static class RFC3211Wrap
+ extends BaseWrapCipher
+ {
+ public RFC3211Wrap()
+ {
+ super(new RFC3211WrapEngine(new AESFastEngine()), 16);
+ }
+ }
+
+
+ /**
+ * PBEWithAES-CBC
+ */
+ static public class PBEWithAESCBC
+ extends BaseBlockCipher
+ {
+ public PBEWithAESCBC()
+ {
+ super(new CBCBlockCipher(new AESFastEngine()));
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ this(192);
+ }
+
+ public KeyGen(int keySize)
+ {
+ super("AES", keySize, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGen128
+ extends KeyGen
+ {
+ public KeyGen128()
+ {
+ super(128);
+ }
+ }
+
+ public static class KeyGen192
+ extends KeyGen
+ {
+ public KeyGen192()
+ {
+ super(192);
+ }
+ }
+
+ public static class KeyGen256
+ extends KeyGen
+ {
+ public KeyGen256()
+ {
+ super(256);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And128BitAES-BC
+ */
+ static public class PBEWithSHAAnd128BitAESBC
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAAnd128BitAESBC()
+ {
+ super("PBEWithSHA1And128BitAES-CBC-BC", null, true, PKCS12, SHA1, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And192BitAES-BC
+ */
+ static public class PBEWithSHAAnd192BitAESBC
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAAnd192BitAESBC()
+ {
+ super("PBEWithSHA1And192BitAES-CBC-BC", null, true, PKCS12, SHA1, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And256BitAES-BC
+ */
+ static public class PBEWithSHAAnd256BitAESBC
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAAnd256BitAESBC()
+ {
+ super("PBEWithSHA1And256BitAES-CBC-BC", null, true, PKCS12, SHA1, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And128BitAES-BC
+ */
+ static public class PBEWithSHA256And128BitAESBC
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHA256And128BitAESBC()
+ {
+ super("PBEWithSHA256And128BitAES-CBC-BC", null, true, PKCS12, SHA256, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And192BitAES-BC
+ */
+ static public class PBEWithSHA256And192BitAESBC
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHA256And192BitAESBC()
+ {
+ super("PBEWithSHA256And192BitAES-CBC-BC", null, true, PKCS12, SHA256, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And256BitAES-BC
+ */
+ static public class PBEWithSHA256And256BitAESBC
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHA256And256BitAESBC()
+ {
+ super("PBEWithSHA256And256BitAES-CBC-BC", null, true, PKCS12, SHA256, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And128BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And128BitAESCBCOpenSSL
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMD5And128BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And192BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And192BitAESCBCOpenSSL
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMD5And192BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And192BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And256BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And256BitAESCBCOpenSSL
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMD5And256BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And256BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128);
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[16];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "AES IV";
+ }
+ }
+
+ public static class AlgParamsGCM
+ extends BaseAlgorithmParameters
+ {
+ private GCMParameters gcmParams;
+
+ protected void engineInit(AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (gcmSpecClass != null)
+ {
+ try
+ {
+ Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+ Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+
+ gcmParams = new GCMParameters((byte[])iv.invoke(paramSpec, new Object[0]), ((Integer)tLen.invoke(paramSpec, new Object[0])).intValue());
+ }
+ catch (Exception e)
+ {
+ throw new InvalidParameterSpecException("Cannot process GCMParameterSpec.");
+ }
+ }
+ }
+
+ protected void engineInit(byte[] params)
+ throws IOException
+ {
+ gcmParams = GCMParameters.getInstance(params);
+ }
+
+ protected void engineInit(byte[] params, String format)
+ throws IOException
+ {
+ if (!isASN1FormatString(format))
+ {
+ throw new IOException("unknown format specified");
+ }
+
+ gcmParams = GCMParameters.getInstance(params);
+ }
+
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ return gcmParams.getEncoded();
+ }
+
+ protected byte[] engineGetEncoded(String format)
+ throws IOException
+ {
+ if (!isASN1FormatString(format))
+ {
+ throw new IOException("unknown format specified");
+ }
+
+ return gcmParams.getEncoded();
+ }
+
+ protected String engineToString()
+ {
+ return "GCM";
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (gcmSpecClass != null)
+ {
+ try
+ {
+ Constructor constructor = gcmSpecClass.getConstructor(new Class[] { byte[].class, Integer.class });
+
+ return (AlgorithmParameterSpec)constructor.newInstance(new Object[] { gcmParams.getNonce(), Integers.valueOf(gcmParams.getIcvLen()) });
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new InvalidParameterSpecException("no constructor found!"); // should never happen
+ }
+ catch (Exception e)
+ {
+ throw new InvalidParameterSpecException("construction failed: " + e.getMessage()); // should never happen
+ }
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec: " + paramSpec.getName());
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = AES.class.getName();
+
+ /**
+ * These three got introduced in some messages as a result of a typo in an
+ * early document. We don't produce anything using these OID values, but we'll
+ * read them.
+ */
+ private static final String wrongAES128 = "2.16.840.1.101.3.4.2";
+ private static final String wrongAES192 = "2.16.840.1.101.3.4.22";
+ private static final String wrongAES256 = "2.16.840.1.101.3.4.42";
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.AES", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES128, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES192, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES256, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+
+ provider.addAlgorithm("AlgorithmParameters.GCM", PREFIX + "$AlgParamsGCM");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+
+ provider.addAlgorithm("Cipher.AES", PREFIX + "$ECB");
+ provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES128, "AES");
+ provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES192, "AES");
+ provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES256, "AES");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$OFB");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$OFB");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$OFB");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$CFB");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$CFB");
+ provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$CFB");
+ provider.addAlgorithm("Cipher.AESWRAP", PREFIX + "$Wrap");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
+ provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
+
+ provider.addAlgorithm("Cipher.GCM", PREFIX + "$GCM");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
+
+ provider.addAlgorithm("KeyGenerator.AES", PREFIX + "$KeyGen");
+ provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128");
+ provider.addAlgorithm("KeyGenerator." + wrongAES192, PREFIX + "$KeyGen192");
+ provider.addAlgorithm("KeyGenerator." + wrongAES256, PREFIX + "$KeyGen256");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$KeyGen128");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$KeyGen128");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$KeyGen128");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$KeyGen128");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$KeyGen192");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$KeyGen192");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$KeyGen192");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$KeyGen192");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$KeyGen256");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$KeyGen256");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$KeyGen256");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$KeyGen256");
+ provider.addAlgorithm("KeyGenerator.AESWRAP", PREFIX + "$KeyGen");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, PREFIX + "$KeyGen128");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, PREFIX + "$KeyGen192");
+ provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, PREFIX + "$KeyGen256");
+
+ provider.addAlgorithm("Mac.AESCMAC", PREFIX + "$AESCMAC");
+
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PBEWITHSHAAND256BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
+
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
+ provider.addAlgorithm("Cipher.PBEWITHSHA256AND128BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
+ provider.addAlgorithm("Cipher.PBEWITHSHA256AND192BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
+ provider.addAlgorithm("Cipher.PBEWITHSHA256AND256BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
+
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+
+ provider.addAlgorithm("Cipher.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
+ provider.addAlgorithm("Cipher.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
+ provider.addAlgorithm("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And128BitAESCBCOpenSSL");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And192BitAESCBCOpenSSL");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithMD5And256BitAESCBCOpenSSL");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND128BITAES-CBC-BC", PREFIX + "$PBEWithSHAAnd128BitAESBC");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND192BITAES-CBC-BC", PREFIX + "$PBEWithSHAAnd192BitAESBC");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND256BITAES-CBC-BC", PREFIX + "$PBEWithSHAAnd256BitAESBC");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA256AND128BITAES-CBC-BC", PREFIX + "$PBEWithSHA256And128BitAESBC");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA256AND192BITAES-CBC-BC", PREFIX + "$PBEWithSHA256And192BitAESBC");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA256AND256BITAES-CBC-BC", PREFIX + "$PBEWithSHA256And256BitAESBC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PBEWITHSHAAND256BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND256BITAES-CBC-BC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND128BITAES-CBC-BC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND192BITAES-CBC-BC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND256BITAES-CBC-BC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND128BITAES-CBC-BC","PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND192BITAES-CBC-BC","PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND256BITAES-CBC-BC","PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND128BITAES-CBC-BC","PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND192BITAES-CBC-BC","PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND256BITAES-CBC-BC","PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND128BITAES-CBC-BC","PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND192BITAES-CBC-BC","PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND256BITAES-CBC-BC","PKCS12PBE");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
+
+ addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
+ addPoly1305Algorithm(provider, "AES", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+ }
+ }
+
+ private static Class lookup(String className)
+ {
+ try
+ {
+ Class def = AES.class.getClassLoader().loadClass(className);
+
+ return def;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/ARC4.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/ARC4.java
new file mode 100644
index 000000000..b50711b12
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/ARC4.java
@@ -0,0 +1,124 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.RC4Engine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class ARC4
+{
+ private ARC4()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new RC4Engine(), 0);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("RC4", 128, new CipherKeyGenerator());
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC4
+ */
+ static public class PBEWithSHAAnd128BitKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAAnd128BitKeyFactory()
+ {
+ super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 128, 0);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC4
+ */
+ static public class PBEWithSHAAnd40BitKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAAnd40BitKeyFactory()
+ {
+ super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 40, 0);
+ }
+ }
+
+
+ /**
+ * PBEWithSHAAnd128BitRC4
+ */
+ static public class PBEWithSHAAnd128Bit
+ extends BaseStreamCipher
+ {
+ public PBEWithSHAAnd128Bit()
+ {
+ super(new RC4Engine(), 0);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC4
+ */
+ static public class PBEWithSHAAnd40Bit
+ extends BaseStreamCipher
+ {
+ public PBEWithSHAAnd40Bit()
+ {
+ super(new RC4Engine(), 0);
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = ARC4.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.ARC4", PREFIX + "$Base");
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.rc4, "ARC4");
+ provider.addAlgorithm("Alg.Alias.Cipher.ARCFOUR", "ARC4");
+ provider.addAlgorithm("Alg.Alias.Cipher.RC4", "ARC4");
+ provider.addAlgorithm("KeyGenerator.ARC4", PREFIX + "$KeyGen");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.RC4", "ARC4");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "ARC4");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND128BITRC4", PREFIX + "$PBEWithSHAAnd128BitKeyFactory");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND40BITRC4", PREFIX + "$PBEWithSHAAnd40BitKeyFactory");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC4", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC4", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC4", "PKCS12PBE");
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITRC4", PREFIX + "$PBEWithSHAAnd128Bit");
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND40BITRC4", PREFIX + "$PBEWithSHAAnd40Bit");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PBEWITHSHAAND128BITRC4");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PBEWITHSHAAND40BITRC4");
+
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "PBEWITHSHAAND128BITRC4");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "PBEWITHSHAAND40BITRC4");
+
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PBEWITHSHAAND128BITRC4");
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PBEWITHSHAAND40BITRC4");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Blowfish.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Blowfish.java
new file mode 100644
index 000000000..152d29b16
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Blowfish.java
@@ -0,0 +1,75 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.BlowfishEngine;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Blowfish
+{
+ private Blowfish()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlowfishEngine());
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new BlowfishEngine()), 64);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Blowfish", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Blowfish IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Blowfish.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.BLOWFISH", PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher.1.3.6.1.4.1.3029.1.2", PREFIX + "$CBC");
+ provider.addAlgorithm("KeyGenerator.BLOWFISH", PREFIX + "$KeyGen");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
+ provider.addAlgorithm("AlgorithmParameters.BLOWFISH", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/CAST5.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/CAST5.java
new file mode 100644
index 000000000..9de0707ee
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/CAST5.java
@@ -0,0 +1,221 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.misc.CAST5CBCParameters;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.CAST5Engine;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class CAST5
+{
+ private CAST5()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new CAST5Engine());
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new CAST5Engine()), 64);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("CAST5", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for CAST5 parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[8];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("CAST5", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends BaseAlgorithmParameters
+ {
+ private byte[] iv;
+ private int keyLength = 128;
+
+ protected byte[] engineGetEncoded()
+ {
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, iv.length);
+ return tmp;
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return new CAST5CBCParameters(engineGetEncoded(), keyLength).getEncoded();
+ }
+
+ if (format.equals("RAW"))
+ {
+ return engineGetEncoded();
+ }
+
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to CAST5 parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec instanceof IvParameterSpec)
+ {
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+ else
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec required to initialise a CAST5 parameters algorithm parameters object");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.iv = new byte[params.length];
+
+ System.arraycopy(params, 0, iv, 0, iv.length);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+ CAST5CBCParameters p = CAST5CBCParameters.getInstance(aIn.readObject());
+
+ keyLength = p.getKeyLength();
+
+ iv = p.getIV();
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "CAST5 Parameters";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = CAST5.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("AlgorithmParameters.CAST5", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113533.7.66.10", "CAST5");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.CAST5", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.1.2.840.113533.7.66.10", "CAST5");
+
+ provider.addAlgorithm("Cipher.CAST5", PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher.1.2.840.113533.7.66.10", PREFIX + "$CBC");
+
+ provider.addAlgorithm("KeyGenerator.CAST5", PREFIX + "$KeyGen");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.1.2.840.113533.7.66.10", "CAST5");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/CAST6.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/CAST6.java
new file mode 100644
index 000000000..be5f62b37
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/CAST6.java
@@ -0,0 +1,90 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.CAST6Engine;
+import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
+import org.spongycastle.crypto.macs.GMac;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+
+public final class CAST6
+{
+ private CAST6()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new CAST6Engine();
+ }
+ });
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("CAST6", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new CAST6Engine())));
+ }
+ }
+
+ public static class Poly1305
+ extends BaseMac
+ {
+ public Poly1305()
+ {
+ super(new org.spongycastle.crypto.macs.Poly1305(new CAST6Engine()));
+ }
+ }
+
+ public static class Poly1305KeyGen
+ extends BaseKeyGenerator
+ {
+ public Poly1305KeyGen()
+ {
+ super("Poly1305-CAST6", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = CAST6.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.CAST6", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.CAST6", PREFIX + "$KeyGen");
+
+ addGMacAlgorithm(provider, "CAST6", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+ addPoly1305Algorithm(provider, "CAST6", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Camellia.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Camellia.java
new file mode 100644
index 000000000..6724d2af2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Camellia.java
@@ -0,0 +1,238 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.CamelliaEngine;
+import org.spongycastle.crypto.engines.CamelliaWrapEngine;
+import org.spongycastle.crypto.engines.RFC3211WrapEngine;
+import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
+import org.spongycastle.crypto.macs.GMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class Camellia
+{
+ private Camellia()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new CamelliaEngine();
+ }
+ });
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new CamelliaEngine()), 128);
+ }
+ }
+
+ public static class Wrap
+ extends BaseWrapCipher
+ {
+ public Wrap()
+ {
+ super(new CamelliaWrapEngine());
+ }
+ }
+
+ public static class RFC3211Wrap
+ extends BaseWrapCipher
+ {
+ public RFC3211Wrap()
+ {
+ super(new RFC3211WrapEngine(new CamelliaEngine()), 16);
+ }
+ }
+
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new CamelliaEngine())));
+ }
+ }
+
+ public static class Poly1305
+ extends BaseMac
+ {
+ public Poly1305()
+ {
+ super(new org.spongycastle.crypto.macs.Poly1305(new CamelliaEngine()));
+ }
+ }
+
+ public static class Poly1305KeyGen
+ extends BaseKeyGenerator
+ {
+ public Poly1305KeyGen()
+ {
+ super("Poly1305-Camellia", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ this(256);
+ }
+
+ public KeyGen(int keySize)
+ {
+ super("Camellia", keySize, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGen128
+ extends KeyGen
+ {
+ public KeyGen128()
+ {
+ super(128);
+ }
+ }
+
+ public static class KeyGen192
+ extends KeyGen
+ {
+ public KeyGen192()
+ {
+ super(192);
+ }
+ }
+
+ public static class KeyGen256
+ extends KeyGen
+ {
+ public KeyGen256()
+ {
+ super(256);
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for Camellia parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[16];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("Camellia", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Camellia IV";
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = Camellia.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("AlgorithmParameters.CAMELLIA", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NTTObjectIdentifiers.id_camellia128_cbc, "CAMELLIA");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NTTObjectIdentifiers.id_camellia192_cbc, "CAMELLIA");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NTTObjectIdentifiers.id_camellia256_cbc, "CAMELLIA");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.CAMELLIA", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NTTObjectIdentifiers.id_camellia128_cbc, "CAMELLIA");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NTTObjectIdentifiers.id_camellia192_cbc, "CAMELLIA");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NTTObjectIdentifiers.id_camellia256_cbc, "CAMELLIA");
+
+ provider.addAlgorithm("Cipher.CAMELLIA", PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher." + NTTObjectIdentifiers.id_camellia128_cbc, PREFIX + "$CBC");
+ provider.addAlgorithm("Cipher." + NTTObjectIdentifiers.id_camellia192_cbc, PREFIX + "$CBC");
+ provider.addAlgorithm("Cipher." + NTTObjectIdentifiers.id_camellia256_cbc, PREFIX + "$CBC");
+
+ provider.addAlgorithm("Cipher.CAMELLIARFC3211WRAP", PREFIX + "$RFC3211Wrap");
+ provider.addAlgorithm("Cipher.CAMELLIAWRAP", PREFIX + "$Wrap");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NTTObjectIdentifiers.id_camellia128_wrap, "CAMELLIAWRAP");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NTTObjectIdentifiers.id_camellia192_wrap, "CAMELLIAWRAP");
+ provider.addAlgorithm("Alg.Alias.Cipher." + NTTObjectIdentifiers.id_camellia256_wrap, "CAMELLIAWRAP");
+
+ provider.addAlgorithm("KeyGenerator.CAMELLIA", PREFIX + "$KeyGen");
+ provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia128_wrap, PREFIX + "$KeyGen128");
+ provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia192_wrap, PREFIX + "$KeyGen192");
+ provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia256_wrap, PREFIX + "$KeyGen256");
+ provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia128_cbc, PREFIX + "$KeyGen128");
+ provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia192_cbc, PREFIX + "$KeyGen192");
+ provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia256_cbc, PREFIX + "$KeyGen256");
+
+ addGMacAlgorithm(provider, "CAMELLIA", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+ addPoly1305Algorithm(provider, "CAMELLIA", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/ChaCha.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/ChaCha.java
new file mode 100644
index 000000000..406a3f0cc
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/ChaCha.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.ChaChaEngine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class ChaCha
+{
+ private ChaCha()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new ChaChaEngine(), 8);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("ChaCha", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = ChaCha.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.CHACHA", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.CHACHA", PREFIX + "$KeyGen");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/DES.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/DES.java
new file mode 100644
index 000000000..d35cd046c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/DES.java
@@ -0,0 +1,505 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.KeyGenerationParameters;
+import org.spongycastle.crypto.engines.DESEngine;
+import org.spongycastle.crypto.engines.RFC3211WrapEngine;
+import org.spongycastle.crypto.generators.DESKeyGenerator;
+import org.spongycastle.crypto.macs.CBCBlockCipherMac;
+import org.spongycastle.crypto.macs.CFBBlockCipherMac;
+import org.spongycastle.crypto.macs.CMac;
+import org.spongycastle.crypto.macs.ISO9797Alg3Mac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.paddings.ISO7816d4Padding;
+import org.spongycastle.crypto.params.DESParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.PBE;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class DES
+{
+ private DES()
+ {
+ }
+
+ static public class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new DESEngine());
+ }
+ }
+
+ static public class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new DESEngine()), 64);
+ }
+ }
+
+ /**
+ * DES CFB8
+ */
+ public static class DESCFB8
+ extends BaseMac
+ {
+ public DESCFB8()
+ {
+ super(new CFBBlockCipherMac(new DESEngine()));
+ }
+ }
+
+ /**
+ * DES64
+ */
+ public static class DES64
+ extends BaseMac
+ {
+ public DES64()
+ {
+ super(new CBCBlockCipherMac(new DESEngine(), 64));
+ }
+ }
+
+ /**
+ * DES64with7816-4Padding
+ */
+ public static class DES64with7816d4
+ extends BaseMac
+ {
+ public DES64with7816d4()
+ {
+ super(new CBCBlockCipherMac(new DESEngine(), 64, new ISO7816d4Padding()));
+ }
+ }
+
+ public static class CBCMAC
+ extends BaseMac
+ {
+ public CBCMAC()
+ {
+ super(new CBCBlockCipherMac(new DESEngine()));
+ }
+ }
+
+ static public class CMAC
+ extends BaseMac
+ {
+ public CMAC()
+ {
+ super(new CMac(new DESEngine()));
+ }
+ }
+
+ /**
+ * DES9797Alg3with7816-4Padding
+ */
+ public static class DES9797Alg3with7816d4
+ extends BaseMac
+ {
+ public DES9797Alg3with7816d4()
+ {
+ super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
+ }
+ }
+
+ /**
+ * DES9797Alg3
+ */
+ public static class DES9797Alg3
+ extends BaseMac
+ {
+ public DES9797Alg3()
+ {
+ super(new ISO9797Alg3Mac(new DESEngine()));
+ }
+ }
+
+ public static class RFC3211
+ extends BaseWrapCipher
+ {
+ public RFC3211()
+ {
+ super(new RFC3211WrapEngine(new DESEngine()), 8);
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[8];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ /**
+ * DES - the default for this is to generate a key in
+ * a-b-a format that's 24 bytes long but has 16 bytes of
+ * key material (the first 8 bytes is repeated as the last
+ * 8 bytes). If you give it a size, you'll get just what you
+ * asked for.
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("DES", 64, new DESKeyGenerator());
+ }
+
+ protected void engineInit(
+ int keySize,
+ SecureRandom random)
+ {
+ super.engineInit(keySize, random);
+ }
+
+ protected SecretKey engineGenerateKey()
+ {
+ if (uninitialised)
+ {
+ engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+ uninitialised = false;
+ }
+
+ return new SecretKeySpec(engine.generateKey(), algName);
+ }
+ }
+
+ static public class KeyFactory
+ extends BaseSecretKeyFactory
+ {
+ public KeyFactory()
+ {
+ super("DES", null);
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+ else if (DESKeySpec.class.isAssignableFrom(keySpec))
+ {
+ byte[] bytes = key.getEncoded();
+
+ try
+ {
+ return new DESKeySpec(bytes);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESKeySpec)
+ {
+ DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DES");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ static public class DESPBEKeyFactory
+ extends BaseSecretKeyFactory
+ {
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public DESPBEKeyFactory(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ if (forCipher)
+ {
+ param = PBE.Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+ }
+ else
+ {
+ param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+ }
+
+ KeyParameter kParam;
+ if (param instanceof ParametersWithIV)
+ {
+ kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ kParam = (KeyParameter)param;
+ }
+
+ DESParameters.setOddParity(kParam.getKey());
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ /**
+ * PBEWithMD2AndDES
+ */
+ static public class PBEWithMD2KeyFactory
+ extends DESPBEKeyFactory
+ {
+ public PBEWithMD2KeyFactory()
+ {
+ super("PBEwithMD2andDES", PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, true, PKCS5S1, MD2, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithMD5AndDES
+ */
+ static public class PBEWithMD5KeyFactory
+ extends DESPBEKeyFactory
+ {
+ public PBEWithMD5KeyFactory()
+ {
+ super("PBEwithMD5andDES", PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, true, PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndDES
+ */
+ static public class PBEWithSHA1KeyFactory
+ extends DESPBEKeyFactory
+ {
+ public PBEWithSHA1KeyFactory()
+ {
+ super("PBEwithSHA1andDES", PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, true, PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithMD2AndDES
+ */
+ static public class PBEWithMD2
+ extends BaseBlockCipher
+ {
+ public PBEWithMD2()
+ {
+ super(new CBCBlockCipher(new DESEngine()));
+ }
+ }
+
+ /**
+ * PBEWithMD5AndDES
+ */
+ static public class PBEWithMD5
+ extends BaseBlockCipher
+ {
+ public PBEWithMD5()
+ {
+ super(new CBCBlockCipher(new DESEngine()));
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndDES
+ */
+ static public class PBEWithSHA1
+ extends BaseBlockCipher
+ {
+ public PBEWithSHA1()
+ {
+ super(new CBCBlockCipher(new DESEngine()));
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = DES.class.getName();
+ private static final String PACKAGE = "org.spongycastle.jcajce.provider.symmetric"; // JDK 1.2
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.DES", PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher." + OIWObjectIdentifiers.desCBC, PREFIX + "$CBC");
+
+ addAlias(provider, OIWObjectIdentifiers.desCBC, "DES");
+
+ provider.addAlgorithm("Cipher.DESRFC3211WRAP", PREFIX + "$RFC3211");
+
+ provider.addAlgorithm("KeyGenerator.DES", PREFIX + "$KeyGenerator");
+
+ provider.addAlgorithm("SecretKeyFactory.DES", PREFIX + "$KeyFactory");
+
+ provider.addAlgorithm("Mac.DESCMAC", PREFIX + "$CMAC");
+ provider.addAlgorithm("Mac.DESMAC", PREFIX + "$CBCMAC");
+ provider.addAlgorithm("Alg.Alias.Mac.DES", "DESMAC");
+
+ provider.addAlgorithm("Mac.DESMAC/CFB8", PREFIX + "$DESCFB8");
+ provider.addAlgorithm("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
+
+ provider.addAlgorithm("Mac.DESMAC64", PREFIX + "$DES64");
+ provider.addAlgorithm("Alg.Alias.Mac.DES64", "DESMAC64");
+
+ provider.addAlgorithm("Mac.DESMAC64WITHISO7816-4PADDING", PREFIX + "$DES64with7816d4");
+ provider.addAlgorithm("Alg.Alias.Mac.DES64WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+ provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1MACWITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+ provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+
+ provider.addAlgorithm("Mac.DESWITHISO9797", PREFIX + "$DES9797Alg3");
+ provider.addAlgorithm("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
+
+ provider.addAlgorithm("Mac.ISO9797ALG3MAC", PREFIX + "$DES9797Alg3");
+ provider.addAlgorithm("Alg.Alias.Mac.ISO9797ALG3", "ISO9797ALG3MAC");
+ provider.addAlgorithm("Mac.ISO9797ALG3WITHISO7816-4PADDING", PREFIX + "$DES9797Alg3with7816d4");
+ provider.addAlgorithm("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
+
+ provider.addAlgorithm("AlgorithmParameters.DES", PACKAGE + ".util.IvAlgorithmParameters");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.DES", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "DES");
+
+ provider.addAlgorithm("Cipher.PBEWITHMD2ANDDES", PREFIX + "$PBEWithMD2");
+ provider.addAlgorithm("Cipher.PBEWITHMD5ANDDES", PREFIX + "$PBEWithMD5");
+ provider.addAlgorithm("Cipher.PBEWITHSHA1ANDDES", PREFIX + "$PBEWithSHA1");
+
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHMD2ANDDES", PREFIX + "$PBEWithMD2KeyFactory");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5ANDDES", PREFIX + "$PBEWithMD5KeyFactory");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA1ANDDES", PREFIX + "$PBEWithSHA1KeyFactory");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDDES-CBC", "PBEWITHMD2ANDDES");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHMD5ANDDES-CBC", "PBEWITHMD5ANDDES");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDDES-CBC", "PBEWITHSHA1ANDDES");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+ }
+
+ private void addAlias(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+ {
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + oid.getId(), name);
+ provider.addAlgorithm("Alg.Alias.KeyFactory." + oid.getId(), name);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/DESede.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/DESede.java
new file mode 100644
index 000000000..3c7cbb867
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/DESede.java
@@ -0,0 +1,435 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.KeyGenerationParameters;
+import org.spongycastle.crypto.engines.DESedeEngine;
+import org.spongycastle.crypto.engines.DESedeWrapEngine;
+import org.spongycastle.crypto.engines.RFC3211WrapEngine;
+import org.spongycastle.crypto.generators.DESedeKeyGenerator;
+import org.spongycastle.crypto.macs.CBCBlockCipherMac;
+import org.spongycastle.crypto.macs.CFBBlockCipherMac;
+import org.spongycastle.crypto.macs.CMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.paddings.ISO7816d4Padding;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class DESede
+{
+ private DESede()
+ {
+ }
+
+ static public class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new DESedeEngine());
+ }
+ }
+
+ static public class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()), 64);
+ }
+ }
+
+ /**
+ * DESede CFB8
+ */
+ public static class DESedeCFB8
+ extends BaseMac
+ {
+ public DESedeCFB8()
+ {
+ super(new CFBBlockCipherMac(new DESedeEngine()));
+ }
+ }
+
+ /**
+ * DESede64
+ */
+ public static class DESede64
+ extends BaseMac
+ {
+ public DESede64()
+ {
+ super(new CBCBlockCipherMac(new DESedeEngine(), 64));
+ }
+ }
+
+ /**
+ * DESede64with7816-4Padding
+ */
+ public static class DESede64with7816d4
+ extends BaseMac
+ {
+ public DESede64with7816d4()
+ {
+ super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
+ }
+ }
+
+ public static class CBCMAC
+ extends BaseMac
+ {
+ public CBCMAC()
+ {
+ super(new CBCBlockCipherMac(new DESedeEngine()));
+ }
+ }
+
+ static public class CMAC
+ extends BaseMac
+ {
+ public CMAC()
+ {
+ super(new CMac(new DESedeEngine()));
+ }
+ }
+
+ public static class Wrap
+ extends BaseWrapCipher
+ {
+ public Wrap()
+ {
+ super(new DESedeWrapEngine());
+ }
+ }
+
+ public static class RFC3211
+ extends BaseWrapCipher
+ {
+ public RFC3211()
+ {
+ super(new RFC3211WrapEngine(new DESedeEngine()), 8);
+ }
+ }
+
+ /**
+ * DESede - the default for this is to generate a key in
+ * a-b-a format that's 24 bytes long but has 16 bytes of
+ * key material (the first 8 bytes is repeated as the last
+ * 8 bytes). If you give it a size, you'll get just what you
+ * asked for.
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ private boolean keySizeSet = false;
+
+ public KeyGenerator()
+ {
+ super("DESede", 192, new DESedeKeyGenerator());
+ }
+
+ protected void engineInit(
+ int keySize,
+ SecureRandom random)
+ {
+ super.engineInit(keySize, random);
+ keySizeSet = true;
+ }
+
+ protected SecretKey engineGenerateKey()
+ {
+ if (uninitialised)
+ {
+ engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+ uninitialised = false;
+ }
+
+ //
+ // if no key size has been defined generate a 24 byte key in
+ // the a-b-a format
+ //
+ if (!keySizeSet)
+ {
+ byte[] k = engine.generateKey();
+
+ System.arraycopy(k, 0, k, 16, 8);
+
+ return new SecretKeySpec(k, algName);
+ }
+ else
+ {
+ return new SecretKeySpec(engine.generateKey(), algName);
+ }
+ }
+ }
+
+ /**
+ * generate a desEDE key in the a-b-c format.
+ */
+ public static class KeyGenerator3
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator3()
+ {
+ super("DESede3", 192, new DESedeKeyGenerator());
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd3-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES3Key
+ extends BaseBlockCipher
+ {
+ public PBEWithSHAAndDES3Key()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()));
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd2-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES2Key
+ extends BaseBlockCipher
+ {
+ public PBEWithSHAAndDES2Key()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()));
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd3-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES3KeyFactory
+ extends DES.DESPBEKeyFactory
+ {
+ public PBEWithSHAAndDES3KeyFactory()
+ {
+ super("PBEwithSHAandDES3Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, true, PKCS12, SHA1, 192, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd2-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES2KeyFactory
+ extends DES.DESPBEKeyFactory
+ {
+ public PBEWithSHAAndDES2KeyFactory()
+ {
+ super("PBEwithSHAandDES2Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[8];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ static public class KeyFactory
+ extends BaseSecretKeyFactory
+ {
+ public KeyFactory()
+ {
+ super("DESede", null);
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+ else if (DESedeKeySpec.class.isAssignableFrom(keySpec))
+ {
+ byte[] bytes = key.getEncoded();
+
+ try
+ {
+ if (bytes.length == 16)
+ {
+ byte[] longKey = new byte[24];
+
+ System.arraycopy(bytes, 0, longKey, 0, 16);
+ System.arraycopy(bytes, 0, longKey, 16, 8);
+
+ return new DESedeKeySpec(longKey);
+ }
+ else
+ {
+ return new DESedeKeySpec(bytes);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESedeKeySpec)
+ {
+ DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DESede");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = DESede.class.getName();
+ private static final String PACKAGE = "org.spongycastle.jcajce.provider.symmetric"; // JDK 1.2
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.DESEDE", PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$CBC");
+ provider.addAlgorithm("Cipher.DESEDEWRAP", PREFIX + "$Wrap");
+ provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, PREFIX + "$Wrap");
+ provider.addAlgorithm("Cipher.DESEDERFC3211WRAP", PREFIX + "$RFC3211");
+
+ provider.addAlgorithm("Alg.Alias.Cipher.TDEA", "DESEDE");
+ provider.addAlgorithm("Alg.Alias.Cipher.TDEAWRAP", "DESEDEWRAP");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.TDEA", "DESEDE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.TDEA", "DESEDE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.TDEA", "DESEDE");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.TDEA", "DESEDE");
+
+ if (provider.hasAlgorithm("MessageDigest", "SHA-1"))
+ {
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3Key");
+ provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES3Key");
+ provider.addAlgorithm("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$OldPBEWithSHAAndDES3Key");
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2Key");
+ provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES2Key");
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+ }
+
+ provider.addAlgorithm("KeyGenerator.DESEDE", PREFIX + "$KeyGenerator");
+ provider.addAlgorithm("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$KeyGenerator3");
+ provider.addAlgorithm("KeyGenerator.DESEDEWRAP", PREFIX + "$KeyGenerator");
+
+ provider.addAlgorithm("SecretKeyFactory.DESEDE", PREFIX + "$KeyFactory");
+
+ provider.addAlgorithm("Mac.DESEDECMAC", PREFIX + "$CMAC");
+ provider.addAlgorithm("Mac.DESEDEMAC", PREFIX + "$CBCMAC");
+ provider.addAlgorithm("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
+
+ provider.addAlgorithm("Mac.DESEDEMAC/CFB8", PREFIX + "$DESedeCFB8");
+ provider.addAlgorithm("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
+
+ provider.addAlgorithm("Mac.DESEDEMAC64", PREFIX + "$DESede64");
+ provider.addAlgorithm("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
+
+ provider.addAlgorithm("Mac.DESEDEMAC64WITHISO7816-4PADDING", PREFIX + "$DESede64with7816d4");
+ provider.addAlgorithm("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+ provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+ provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+
+ provider.addAlgorithm("AlgorithmParameters.DESEDE", PACKAGE + ".util.IvAlgorithmParameters");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.DESEDE", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3KeyFactory");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2KeyFactory");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES3KEY-CBC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES2KEY-CBC", "PKCS12PBE");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.3", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.4", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWithSHAAnd3KeyTripleDES", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.3", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.4", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWithSHAAnd3KeyTripleDES", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/GOST28147.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/GOST28147.java
new file mode 100644
index 000000000..8b4404298
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/GOST28147.java
@@ -0,0 +1,157 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.GOST28147Engine;
+import org.spongycastle.crypto.macs.GOST28147Mac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.GCFBBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class GOST28147
+{
+ private GOST28147()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new GOST28147Engine());
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new GOST28147Engine()), 64);
+ }
+ }
+
+ public static class GCFB
+ extends BaseBlockCipher
+ {
+ public GCFB()
+ {
+ super(new BufferedBlockCipher(new GCFBBlockCipher(new GOST28147Engine())), 64);
+ }
+ }
+
+ /**
+ * GOST28147
+ */
+ public static class Mac
+ extends BaseMac
+ {
+ public Mac()
+ {
+ super(new GOST28147Mac());
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ this(256);
+ }
+
+ public KeyGen(int keySize)
+ {
+ super("GOST28147", keySize, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[16];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("GOST28147", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "GOST IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = GOST28147.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.GOST28147", PREFIX + "$ECB");
+ provider.addAlgorithm("Alg.Alias.Cipher.GOST", "GOST28147");
+ provider.addAlgorithm("Alg.Alias.Cipher.GOST-28147", "GOST28147");
+ provider.addAlgorithm("Cipher." + CryptoProObjectIdentifiers.gostR28147_gcfb, PREFIX + "$GCFB");
+
+ provider.addAlgorithm("KeyGenerator.GOST28147", PREFIX + "$KeyGen");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.GOST", "GOST28147");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.GOST-28147", "GOST28147");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + CryptoProObjectIdentifiers.gostR28147_gcfb, "GOST28147");
+
+ provider.addAlgorithm("Mac.GOST28147MAC", PREFIX + "$Mac");
+ provider.addAlgorithm("Alg.Alias.Mac.GOST28147", "GOST28147MAC");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Grain128.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Grain128.java
new file mode 100644
index 000000000..39f70a362
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Grain128.java
@@ -0,0 +1,49 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.Grain128Engine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Grain128
+{
+ private Grain128()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new Grain128Engine(), 12);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Grain128", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Grain128.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.Grain128", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.Grain128", PREFIX + "$KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Grainv1.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Grainv1.java
new file mode 100644
index 000000000..d5aaf604f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Grainv1.java
@@ -0,0 +1,49 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.Grainv1Engine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Grainv1
+{
+ private Grainv1()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new Grainv1Engine(), 8);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Grainv1", 80, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Grainv1.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.Grainv1", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.Grainv1", PREFIX + "$KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/HC128.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/HC128.java
new file mode 100644
index 000000000..1463a5972
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/HC128.java
@@ -0,0 +1,49 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.HC128Engine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class HC128
+{
+ private HC128()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new HC128Engine(), 16);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("HC128", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = HC128.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.HC128", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.HC128", PREFIX + "$KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/HC256.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/HC256.java
new file mode 100644
index 000000000..126fec273
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/HC256.java
@@ -0,0 +1,49 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.HC256Engine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class HC256
+{
+ private HC256()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new HC256Engine(), 32);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("HC256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = HC256.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.HC256", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.HC256", PREFIX + "$KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/IDEA.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/IDEA.java
new file mode 100644
index 000000000..0650a9b46
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/IDEA.java
@@ -0,0 +1,258 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.misc.IDEACBCPar;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.IDEAEngine;
+import org.spongycastle.crypto.macs.CBCBlockCipherMac;
+import org.spongycastle.crypto.macs.CFBBlockCipherMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class IDEA
+{
+ private IDEA()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new IDEAEngine());
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new IDEAEngine()), 64);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("IDEA", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class PBEWithSHAAndIDEAKeyGen
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAAndIDEAKeyGen()
+ {
+ super("PBEwithSHAandIDEA-CBC", null, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ static public class PBEWithSHAAndIDEA
+ extends BaseBlockCipher
+ {
+ public PBEWithSHAAndIDEA()
+ {
+ super(new CBCBlockCipher(new IDEAEngine()));
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for IDEA parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[8];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("IDEA", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends BaseAlgorithmParameters
+ {
+ private byte[] iv;
+
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ return engineGetEncoded("ASN.1");
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return new IDEACBCPar(engineGetEncoded("RAW")).getEncoded();
+ }
+
+ if (format.equals("RAW"))
+ {
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, iv.length);
+ return tmp;
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof IvParameterSpec))
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+ }
+
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.iv = new byte[params.length];
+
+ System.arraycopy(params, 0, iv, 0, iv.length);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+ if (format.equals("ASN.1"))
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+ IDEACBCPar oct = new IDEACBCPar((ASN1Sequence)aIn.readObject());
+
+ engineInit(oct.getIV());
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "IDEA Parameters";
+ }
+ }
+
+ public static class Mac
+ extends BaseMac
+ {
+ public Mac()
+ {
+ super(new CBCBlockCipherMac(new IDEAEngine()));
+ }
+ }
+
+ public static class CFB8Mac
+ extends BaseMac
+ {
+ public CFB8Mac()
+ {
+ super(new CFBBlockCipherMac(new IDEAEngine()));
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = IDEA.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameterGenerator.IDEA", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("AlgorithmParameterGenerator.1.3.6.1.4.1.188.7.1.1.2", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("AlgorithmParameters.IDEA", PREFIX + "$AlgParams");
+ provider.addAlgorithm("AlgorithmParameters.1.3.6.1.4.1.188.7.1.1.2", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDIDEA", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDIDEA-CBC", "PKCS12PBE");
+ provider.addAlgorithm("Cipher.IDEA", PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher.1.3.6.1.4.1.188.7.1.1.2", PREFIX + "$CBC");
+ provider.addAlgorithm("Cipher.PBEWITHSHAANDIDEA-CBC", PREFIX + "$PBEWithSHAAndIDEA");
+ provider.addAlgorithm("KeyGenerator.IDEA", PREFIX + "$KeyGen");
+ provider.addAlgorithm("KeyGenerator.1.3.6.1.4.1.188.7.1.1.2", PREFIX + "$KeyGen");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAANDIDEA-CBC", PREFIX + "$PBEWithSHAAndIDEAKeyGen");
+ provider.addAlgorithm("Mac.IDEAMAC", PREFIX + "$Mac");
+ provider.addAlgorithm("Alg.Alias.Mac.IDEA", "IDEAMAC");
+ provider.addAlgorithm("Mac.IDEAMAC/CFB8", PREFIX + "$CFB8Mac");
+ provider.addAlgorithm("Alg.Alias.Mac.IDEA/CFB8", "IDEAMAC/CFB8");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Noekeon.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Noekeon.java
new file mode 100644
index 000000000..4342b1024
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Noekeon.java
@@ -0,0 +1,153 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.NoekeonEngine;
+import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
+import org.spongycastle.crypto.macs.GMac;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class Noekeon
+{
+ private Noekeon()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new NoekeonEngine();
+ }
+ });
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Noekeon", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new NoekeonEngine())));
+ }
+ }
+
+ public static class Poly1305
+ extends BaseMac
+ {
+ public Poly1305()
+ {
+ super(new org.spongycastle.crypto.macs.Poly1305(new NoekeonEngine()));
+ }
+ }
+
+ public static class Poly1305KeyGen
+ extends BaseKeyGenerator
+ {
+ public Poly1305KeyGen()
+ {
+ super("Poly1305-Noekeon", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for Noekeon parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[16];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("Noekeon", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Noekeon IV";
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = Noekeon.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("AlgorithmParameters.NOEKEON", PREFIX + "$AlgParams");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.NOEKEON", PREFIX + "$AlgParamGen");
+
+ provider.addAlgorithm("Cipher.NOEKEON", PREFIX + "$ECB");
+
+ provider.addAlgorithm("KeyGenerator.NOEKEON", PREFIX + "$KeyGen");
+
+ addGMacAlgorithm(provider, "NOEKEON", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+ addPoly1305Algorithm(provider, "NOEKEON", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/PBEPBKDF2.java
new file mode 100644
index 000000000..fb3e873d7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/PBEPBKDF2.java
@@ -0,0 +1,228 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
+import org.spongycastle.jcajce.provider.symmetric.util.PBE;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jcajce.spec.PBKDF2KeySpec;
+
+public class PBEPBKDF2
+{
+ private PBEPBKDF2()
+ {
+
+ }
+
+ public static class AlgParams
+ extends BaseAlgorithmParameters
+ {
+ PBKDF2Params params;
+
+ protected byte[] engineGetEncoded()
+ {
+ try
+ {
+ return params.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Oooops! " + e.toString());
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PBEParameterSpec.class)
+ {
+ return new PBEParameterSpec(params.getSalt(),
+ params.getIterationCount().intValue());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PBKDF2 PBE parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PBEParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PBKDF2 PBE parameters algorithm parameters object");
+ }
+
+ PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+ this.params = new PBKDF2Params(pbeSpec.getSalt(),
+ pbeSpec.getIterationCount());
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.params = PBKDF2Params.getInstance(ASN1Primitive.fromByteArray(params));
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in PBKDF2 parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "PBKDF2 Parameters";
+ }
+ }
+
+ public static class BasePBKDF2
+ extends BaseSecretKeyFactory
+ {
+ private int scheme;
+
+ public BasePBKDF2(String name, int scheme)
+ {
+ super(name, PKCSObjectIdentifiers.id_PBKDF2);
+
+ this.scheme = scheme;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ throw new InvalidKeySpecException("missing required salt");
+ }
+
+ if (pbeSpec.getIterationCount() <= 0)
+ {
+ throw new InvalidKeySpecException("positive iteration count required: "
+ + pbeSpec.getIterationCount());
+ }
+
+ if (pbeSpec.getKeyLength() <= 0)
+ {
+ throw new InvalidKeySpecException("positive key length required: "
+ + pbeSpec.getKeyLength());
+ }
+
+ if (pbeSpec.getPassword().length == 0)
+ {
+ throw new IllegalArgumentException("password empty");
+ }
+
+ if (pbeSpec instanceof PBKDF2KeySpec)
+ {
+ PBKDF2KeySpec spec = (PBKDF2KeySpec)pbeSpec;
+
+ int digest = getDigestCode(spec.getPrf().getAlgorithm());
+ int keySize = pbeSpec.getKeyLength();
+ int ivSize = -1; // JDK 1,2 and earlier does not understand simplified version.
+ CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+ else
+ {
+ int digest = SHA1;
+ int keySize = pbeSpec.getKeyLength();
+ int ivSize = -1; // JDK 1,2 and earlier does not understand simplified version.
+ CipherParameters param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+
+ private int getDigestCode(ASN1ObjectIdentifier algorithm)
+ throws InvalidKeySpecException
+ {
+ if (algorithm.equals(CryptoProObjectIdentifiers.gostR3411Hmac))
+ {
+ return GOST3411;
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_hmacWithSHA1))
+ {
+ return SHA1;
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec: unknown PRF algorithm " + algorithm);
+ }
+ }
+
+ public static class PBKDF2withUTF8
+ extends BasePBKDF2
+ {
+ public PBKDF2withUTF8()
+ {
+ super("PBKDF2", PKCS5S2_UTF8);
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = PBEPBKDF2.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.PBKDF2", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
+ provider.addAlgorithm("SecretKeyFactory.PBKDF2", PREFIX + "$PBKDF2withUTF8");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/PBEPKCS12.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/PBEPKCS12.java
new file mode 100644
index 000000000..e9a918e85
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/PBEPKCS12.java
@@ -0,0 +1,120 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public class PBEPKCS12
+{
+ private PBEPKCS12()
+ {
+
+ }
+
+ public static class AlgParams
+ extends BaseAlgorithmParameters
+ {
+ PKCS12PBEParams params;
+
+ protected byte[] engineGetEncoded()
+ {
+ try
+ {
+ return params.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Oooops! " + e.toString());
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PBEParameterSpec.class)
+ {
+ return new PBEParameterSpec(params.getIV(),
+ params.getIterations().intValue());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PBEParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+ }
+
+ PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+ this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
+ pbeSpec.getIterationCount());
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.params = PKCS12PBEParams.getInstance(ASN1Primitive.fromByteArray(params));
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "PKCS12 PBE Parameters";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = PBEPKCS12.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.PKCS12PBE", PREFIX + "$AlgParams");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC2.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC2.java
new file mode 100644
index 000000000..4a72b2451
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC2.java
@@ -0,0 +1,523 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RC2CBCParameter;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.RC2Engine;
+import org.spongycastle.crypto.engines.RC2WrapEngine;
+import org.spongycastle.crypto.macs.CBCBlockCipherMac;
+import org.spongycastle.crypto.macs.CFBBlockCipherMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Arrays;
+
+public final class RC2
+{
+ private RC2()
+ {
+ }
+
+ /**
+ * RC2
+ */
+ static public class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new RC2Engine());
+ }
+ }
+
+ /**
+ * RC2CBC
+ */
+ static public class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new RC2Engine()), 64);
+ }
+ }
+
+ public static class Wrap
+ extends BaseWrapCipher
+ {
+ public Wrap()
+ {
+ super(new RC2WrapEngine());
+ }
+ }
+
+ /**
+ * RC2
+ */
+ public static class CBCMAC
+ extends BaseMac
+ {
+ public CBCMAC()
+ {
+ super(new CBCBlockCipherMac(new RC2Engine()));
+ }
+ }
+
+ public static class CFB8MAC
+ extends BaseMac
+ {
+ public CFB8MAC()
+ {
+ super(new CFBBlockCipherMac(new RC2Engine()));
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndRC2
+ */
+ static public class PBEWithSHA1KeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHA1KeyFactory()
+ {
+ super("PBEwithSHA1andRC2", PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, true, PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd128BitKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAAnd128BitKeyFactory()
+ {
+ super("PBEwithSHAand128BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd40BitKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAAnd40BitKeyFactory()
+ {
+ super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64);
+ }
+ }
+
+ /**
+ * PBEWithMD5AndRC2
+ */
+ static public class PBEWithMD5AndRC2
+ extends BaseBlockCipher
+ {
+ public PBEWithMD5AndRC2()
+ {
+ super(new CBCBlockCipher(new RC2Engine()));
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndRC2
+ */
+ static public class PBEWithSHA1AndRC2
+ extends BaseBlockCipher
+ {
+ public PBEWithSHA1AndRC2()
+ {
+ super(new CBCBlockCipher(new RC2Engine()));
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd128BitRC2
+ extends BaseBlockCipher
+ {
+ public PBEWithSHAAnd128BitRC2()
+ {
+ super(new CBCBlockCipher(new RC2Engine()));
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd40BitRC2
+ extends BaseBlockCipher
+ {
+ public PBEWithSHAAnd40BitRC2()
+ {
+ super(new CBCBlockCipher(new RC2Engine()));
+ }
+ }
+
+ /**
+ * PBEWithMD2AndRC2
+ */
+ static public class PBEWithMD2KeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMD2KeyFactory()
+ {
+ super("PBEwithMD2andRC2", PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, true, PKCS5S1, MD2, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithMD5AndRC2
+ */
+ static public class PBEWithMD5KeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithMD5KeyFactory()
+ {
+ super("PBEwithMD5andRC2", PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, true, PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ RC2ParameterSpec spec = null;
+
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (genParamSpec instanceof RC2ParameterSpec)
+ {
+ spec = (RC2ParameterSpec)genParamSpec;
+ return;
+ }
+
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC2 parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ AlgorithmParameters params;
+
+ if (spec == null)
+ {
+ byte[] iv = new byte[8];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+ else
+ {
+ try
+ {
+ params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(spec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ return params;
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("RC2", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParams
+ extends BaseAlgorithmParameters
+ {
+ private static final short[] table = {
+ 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+ 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+ 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+ 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+ 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+ 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+ 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+ 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+ 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+ 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+ 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+ 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+ 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+ 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+ 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+ 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
+ };
+
+ private static final short[] ekb = {
+ 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
+ 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
+ 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+ 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+ 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+ 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+ 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+ 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+ 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+ 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+ 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+ 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+ 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+ 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+ 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
+ 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
+ };
+
+ private byte[] iv;
+ private int parameterVersion = 58;
+
+ protected byte[] engineGetEncoded()
+ {
+ return Arrays.clone(iv);
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ if (parameterVersion == -1)
+ {
+ return new RC2CBCParameter(engineGetEncoded()).getEncoded();
+ }
+ else
+ {
+ return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
+ }
+ }
+
+ if (format.equals("RAW"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == RC2ParameterSpec.class)
+ {
+ if (parameterVersion != -1)
+ {
+ if (parameterVersion < 256)
+ {
+ return new RC2ParameterSpec(ekb[parameterVersion], iv);
+ }
+ else
+ {
+ return new RC2ParameterSpec(parameterVersion, iv);
+ }
+ }
+ }
+
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec instanceof IvParameterSpec)
+ {
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+ else if (paramSpec instanceof RC2ParameterSpec)
+ {
+ int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+ if (effKeyBits != -1)
+ {
+ if (effKeyBits < 256)
+ {
+ parameterVersion = table[effKeyBits];
+ }
+ else
+ {
+ parameterVersion = effKeyBits;
+ }
+ }
+
+ this.iv = ((RC2ParameterSpec)paramSpec).getIV();
+ }
+ else
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.iv = Arrays.clone(params);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Primitive.fromByteArray(params));
+
+ if (p.getRC2ParameterVersion() != null)
+ {
+ parameterVersion = p.getRC2ParameterVersion().intValue();
+ }
+
+ iv = p.getIV();
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "RC2 Parameters";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = RC2.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.RC2", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("AlgorithmParameterGenerator.1.2.840.113549.3.2", PREFIX + "$AlgParamGen");
+
+ provider.addAlgorithm("KeyGenerator.RC2", PREFIX + "$KeyGenerator");
+ provider.addAlgorithm("KeyGenerator.1.2.840.113549.3.2", PREFIX + "$KeyGenerator");
+
+ provider.addAlgorithm("AlgorithmParameters.RC2", PREFIX + "$AlgParams");
+ provider.addAlgorithm("AlgorithmParameters.1.2.840.113549.3.2", PREFIX + "$AlgParams");
+
+ provider.addAlgorithm("Cipher.RC2", PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher.RC2WRAP", PREFIX + "$Wrap");
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2WRAP");
+ provider.addAlgorithm("Cipher.1.2.840.113549.3.2", PREFIX + "$CBC");
+
+ provider.addAlgorithm("Mac.RC2MAC", PREFIX + "$CBCMAC");
+ provider.addAlgorithm("Alg.Alias.Mac.RC2", "RC2MAC");
+ provider.addAlgorithm("Mac.RC2MAC/CFB8", PREFIX + "$CFB8MAC");
+ provider.addAlgorithm("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDRC2-CBC", "PBEWITHMD2ANDRC2");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHMD5ANDRC2-CBC", "PBEWITHMD5ANDRC2");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDRC2-CBC", "PBEWITHSHA1ANDRC2");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
+
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
+ provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHMD2ANDRC2", PREFIX + "$PBEWithMD2KeyFactory");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5ANDRC2", PREFIX + "$PBEWithMD5KeyFactory");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA1ANDRC2", PREFIX + "$PBEWithSHA1KeyFactory");
+
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND128BITRC2-CBC", PREFIX + "$PBEWithSHAAnd128BitKeyFactory");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND40BITRC2-CBC", PREFIX + "$PBEWithSHAAnd40BitKeyFactory");
+
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
+
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
+
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
+
+ provider.addAlgorithm("Alg.Alias.Cipher.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
+ provider.addAlgorithm("Alg.Alias.Cipher.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "PBEWITHSHAAND128BITRC2-CBC");
+ provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC");
+ provider.addAlgorithm("Cipher.PBEWITHSHA1ANDRC2", PREFIX + "$PBEWithSHA1AndRC2");
+
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITRC2-CBC", PREFIX + "$PBEWithSHAAnd128BitRC2");
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND40BITRC2-CBC", PREFIX + "$PBEWithSHAAnd40BitRC2");
+ provider.addAlgorithm("Cipher.PBEWITHMD5ANDRC2", PREFIX + "$PBEWithMD5AndRC2");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC2", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2-CBC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC2-CBC", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC2-CBC", "PKCS12PBE");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC5.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC5.java
new file mode 100644
index 000000000..53a7a2913
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC5.java
@@ -0,0 +1,177 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.RC532Engine;
+import org.spongycastle.crypto.engines.RC564Engine;
+import org.spongycastle.crypto.macs.CBCBlockCipherMac;
+import org.spongycastle.crypto.macs.CFBBlockCipherMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class RC5
+{
+ private RC5()
+ {
+ }
+
+ /**
+ * RC5
+ */
+ public static class ECB32
+ extends BaseBlockCipher
+ {
+ public ECB32()
+ {
+ super(new RC532Engine());
+ }
+ }
+
+ /**
+ * RC564
+ */
+ public static class ECB64
+ extends BaseBlockCipher
+ {
+ public ECB64()
+ {
+ super(new RC564Engine());
+ }
+ }
+
+ public static class CBC32
+ extends BaseBlockCipher
+ {
+ public CBC32()
+ {
+ super(new CBCBlockCipher(new RC532Engine()), 64);
+ }
+ }
+
+ public static class KeyGen32
+ extends BaseKeyGenerator
+ {
+ public KeyGen32()
+ {
+ super("RC5", 128, new CipherKeyGenerator());
+ }
+ }
+
+ /**
+ * RC5
+ */
+ public static class KeyGen64
+ extends BaseKeyGenerator
+ {
+ public KeyGen64()
+ {
+ super("RC5-64", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC5 parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[8];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("RC5", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class Mac32
+ extends BaseMac
+ {
+ public Mac32()
+ {
+ super(new CBCBlockCipherMac(new RC532Engine()));
+ }
+ }
+
+ public static class CFB8Mac32
+ extends BaseMac
+ {
+ public CFB8Mac32()
+ {
+ super(new CFBBlockCipherMac(new RC532Engine()));
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "RC5 IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = RC5.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.RC5", PREFIX + "$ECB32");
+ provider.addAlgorithm("Alg.Alias.Cipher.RC5-32", "RC5");
+ provider.addAlgorithm("Cipher.RC5-64", PREFIX + "$ECB64");
+ provider.addAlgorithm("KeyGenerator.RC5", PREFIX + "$KeyGen32");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.RC5-32", "RC5");
+ provider.addAlgorithm("KeyGenerator.RC5-64", PREFIX + "$KeyGen64");
+ provider.addAlgorithm("AlgorithmParameters.RC5", PREFIX + "$AlgParams");
+ provider.addAlgorithm("AlgorithmParameters.RC5-64", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Mac.RC5MAC", PREFIX + "$Mac32");
+ provider.addAlgorithm("Alg.Alias.Mac.RC5", "RC5MAC");
+ provider.addAlgorithm("Mac.RC5MAC/CFB8", PREFIX + "$CFB8Mac32");
+ provider.addAlgorithm("Alg.Alias.Mac.RC5/CFB8", "RC5MAC/CFB8");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC6.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC6.java
new file mode 100644
index 000000000..232958f5f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/RC6.java
@@ -0,0 +1,180 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.RC6Engine;
+import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
+import org.spongycastle.crypto.macs.GMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.CFBBlockCipher;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.crypto.modes.OFBBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class RC6
+{
+ private RC6()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new RC6Engine();
+ }
+ });
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new RC6Engine()), 128);
+ }
+ }
+
+ static public class CFB
+ extends BaseBlockCipher
+ {
+ public CFB()
+ {
+ super(new BufferedBlockCipher(new CFBBlockCipher(new RC6Engine(), 128)), 128);
+ }
+ }
+
+ static public class OFB
+ extends BaseBlockCipher
+ {
+ public OFB()
+ {
+ super(new BufferedBlockCipher(new OFBBlockCipher(new RC6Engine(), 128)), 128);
+ }
+ }
+
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new RC6Engine())));
+ }
+ }
+
+ public static class Poly1305
+ extends BaseMac
+ {
+ public Poly1305()
+ {
+ super(new org.spongycastle.crypto.macs.Poly1305(new RC6Engine()));
+ }
+ }
+
+ public static class Poly1305KeyGen
+ extends BaseKeyGenerator
+ {
+ public Poly1305KeyGen()
+ {
+ super("Poly1305-RC6", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("RC6", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC6 parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[16];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("RC6", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "RC6 IV";
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = RC6.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.RC6", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.RC6", PREFIX + "$KeyGen");
+ provider.addAlgorithm("AlgorithmParameters.RC6", PREFIX + "$AlgParams");
+
+ addGMacAlgorithm(provider, "RC6", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+ addPoly1305Algorithm(provider, "RC6", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Rijndael.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Rijndael.java
new file mode 100644
index 000000000..e39df5d57
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Rijndael.java
@@ -0,0 +1,70 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.RijndaelEngine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Rijndael
+{
+ private Rijndael()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new RijndaelEngine();
+ }
+ });
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Rijndael", 192, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Rijndael IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Rijndael.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.RIJNDAEL", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.RIJNDAEL", PREFIX + "$KeyGen");
+ provider.addAlgorithm("AlgorithmParameters.RIJNDAEL", PREFIX + "$AlgParams");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SEED.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SEED.java
new file mode 100644
index 000000000..494f039ee
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SEED.java
@@ -0,0 +1,183 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.asn1.kisa.KISAObjectIdentifiers;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.SEEDEngine;
+import org.spongycastle.crypto.engines.SEEDWrapEngine;
+import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
+import org.spongycastle.crypto.macs.GMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class SEED
+{
+ private SEED()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new SEEDEngine();
+ }
+ });
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new SEEDEngine()), 128);
+ }
+ }
+
+ public static class Wrap
+ extends BaseWrapCipher
+ {
+ public Wrap()
+ {
+ super(new SEEDWrapEngine());
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("SEED", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new SEEDEngine())));
+ }
+ }
+
+ public static class Poly1305
+ extends BaseMac
+ {
+ public Poly1305()
+ {
+ super(new org.spongycastle.crypto.macs.Poly1305(new SEEDEngine()));
+ }
+ }
+
+ public static class Poly1305KeyGen
+ extends BaseKeyGenerator
+ {
+ public Poly1305KeyGen()
+ {
+ super("Poly1305-SEED", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for SEED parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[16];
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("SEED", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "SEED IV";
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = SEED.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("AlgorithmParameters.SEED", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + KISAObjectIdentifiers.id_seedCBC, "SEED");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.SEED", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + KISAObjectIdentifiers.id_seedCBC, "SEED");
+
+ provider.addAlgorithm("Cipher.SEED", PREFIX + "$ECB");
+ provider.addAlgorithm("Cipher." + KISAObjectIdentifiers.id_seedCBC, PREFIX + "$CBC");
+
+ provider.addAlgorithm("Cipher.SEEDWRAP", PREFIX + "$Wrap");
+ provider.addAlgorithm("Alg.Alias.Cipher." + KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWRAP");
+
+ provider.addAlgorithm("KeyGenerator.SEED", PREFIX + "$KeyGen");
+ provider.addAlgorithm("KeyGenerator." + KISAObjectIdentifiers.id_seedCBC, PREFIX + "$KeyGen");
+ provider.addAlgorithm("KeyGenerator." + KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, PREFIX + "$KeyGen");
+
+ addGMacAlgorithm(provider, "SEED", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+ addPoly1305Algorithm(provider, "SEED", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Salsa20.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Salsa20.java
new file mode 100644
index 000000000..6540a0b65
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Salsa20.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.Salsa20Engine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Salsa20
+{
+ private Salsa20()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new Salsa20Engine(), 8);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Salsa20", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Salsa20.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.SALSA20", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.SALSA20", PREFIX + "$KeyGen");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Serpent.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Serpent.java
new file mode 100644
index 000000000..6f2660ad6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Serpent.java
@@ -0,0 +1,103 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.SerpentEngine;
+import org.spongycastle.crypto.engines.TwofishEngine;
+import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
+import org.spongycastle.crypto.macs.GMac;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+
+public final class Serpent
+{
+ private Serpent()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new SerpentEngine();
+ }
+ });
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Serpent", 192, new CipherKeyGenerator());
+ }
+ }
+
+ public static class SerpentGMAC
+ extends BaseMac
+ {
+ public SerpentGMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new SerpentEngine())));
+ }
+ }
+
+ public static class Poly1305
+ extends BaseMac
+ {
+ public Poly1305()
+ {
+ super(new org.spongycastle.crypto.macs.Poly1305(new TwofishEngine()));
+ }
+ }
+
+ public static class Poly1305KeyGen
+ extends BaseKeyGenerator
+ {
+ public Poly1305KeyGen()
+ {
+ super("Poly1305-Serpent", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Serpent IV";
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = Serpent.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.Serpent", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.Serpent", PREFIX + "$KeyGen");
+ provider.addAlgorithm("AlgorithmParameters.Serpent", PREFIX + "$AlgParams");
+
+ addGMacAlgorithm(provider, "SERPENT", PREFIX + "$SerpentGMAC", PREFIX + "$KeyGen");
+ addPoly1305Algorithm(provider, "SERPENT", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Shacal2.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Shacal2.java
new file mode 100644
index 000000000..942544e43
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Shacal2.java
@@ -0,0 +1,124 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.Shacal2Engine;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public final class Shacal2
+{
+ private Shacal2()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new Shacal2Engine();
+ }
+ });
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new Shacal2Engine()), 256);//block size
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Shacal2", 512, new CipherKeyGenerator());//key size
+ }
+ }
+
+ public static class AlgParamGen
+ extends BaseAlgorithmParameterGenerator
+ {
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for Shacal2 parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ byte[] iv = new byte[32];// block size 256
+
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ random.nextBytes(iv);
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("Shacal2", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new IvParameterSpec(iv));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ return params;
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Shacal2 IV";
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = Shacal2.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.Shacal2", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.Shacal2", PREFIX + "$KeyGen");
+ provider.addAlgorithm("AlgorithmParameterGenerator.Shacal2", PREFIX + "$AlgParamGen");
+ provider.addAlgorithm("AlgorithmParameters.Shacal2", PREFIX + "$AlgParams");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SipHash.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SipHash.java
new file mode 100644
index 000000000..82d7e85eb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SipHash.java
@@ -0,0 +1,47 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class SipHash
+{
+ private SipHash()
+ {
+ }
+
+ public static class Mac
+ extends BaseMac
+ {
+ public Mac()
+ {
+ super(new org.spongycastle.crypto.macs.SipHash());
+ }
+ }
+
+ public static class Mac48
+ extends BaseMac
+ {
+ public Mac48()
+ {
+ super(new org.spongycastle.crypto.macs.SipHash(4, 8));
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = SipHash.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Mac.SIPHASH", PREFIX + "$Mac");
+ provider.addAlgorithm("Alg.Alias.Mac.SIPHASH-2-4", "SIPHASH");
+ provider.addAlgorithm("Mac.SIPHASH-4-8", PREFIX + "$Mac48");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Skipjack.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Skipjack.java
new file mode 100644
index 000000000..1f79c547a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Skipjack.java
@@ -0,0 +1,87 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.SkipjackEngine;
+import org.spongycastle.crypto.macs.CBCBlockCipherMac;
+import org.spongycastle.crypto.macs.CFBBlockCipherMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Skipjack
+{
+ private Skipjack()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new SkipjackEngine());
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Skipjack", 80, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Skipjack IV";
+ }
+ }
+
+ public static class Mac
+ extends BaseMac
+ {
+ public Mac()
+ {
+ super(new CBCBlockCipherMac(new SkipjackEngine()));
+ }
+ }
+
+ public static class MacCFB8
+ extends BaseMac
+ {
+ public MacCFB8()
+ {
+ super(new CFBBlockCipherMac(new SkipjackEngine()));
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Skipjack.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.SKIPJACK", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.SKIPJACK", PREFIX + "$KeyGen");
+ provider.addAlgorithm("AlgorithmParameters.SKIPJACK", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Mac.SKIPJACKMAC", PREFIX + "$Mac");
+ provider.addAlgorithm("Alg.Alias.Mac.SKIPJACK", "SKIPJACKMAC");
+ provider.addAlgorithm("Mac.SKIPJACKMAC/CFB8", PREFIX + "$MacCFB8");
+ provider.addAlgorithm("Alg.Alias.Mac.SKIPJACK/CFB8", "SKIPJACKMAC/CFB8");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
new file mode 100644
index 000000000..16a4cd231
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
@@ -0,0 +1,34 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+abstract class SymmetricAlgorithmProvider
+ extends AlgorithmProvider
+{
+ protected void addGMacAlgorithm(
+ ConfigurableProvider provider,
+ String algorithm,
+ String algorithmClassName,
+ String keyGeneratorClassName)
+ {
+ provider.addAlgorithm("Mac." + algorithm + "-GMAC", algorithmClassName);
+ provider.addAlgorithm("Alg.Alias.Mac." + algorithm + "GMAC", algorithm + "-GMAC");
+
+ provider.addAlgorithm("KeyGenerator." + algorithm + "-GMAC", keyGeneratorClassName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "GMAC", algorithm + "-GMAC");
+ }
+
+ protected void addPoly1305Algorithm(ConfigurableProvider provider,
+ String algorithm,
+ String algorithmClassName,
+ String keyGeneratorClassName)
+ {
+ provider.addAlgorithm("Mac.POLY1305-" + algorithm, algorithmClassName);
+ provider.addAlgorithm("Alg.Alias.Mac.POLY1305" + algorithm, "POLY1305-" + algorithm);
+
+ provider.addAlgorithm("KeyGenerator.POLY1305-" + algorithm, keyGeneratorClassName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.POLY1305" + algorithm, "POLY1305-" + algorithm);
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/TEA.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/TEA.java
new file mode 100644
index 000000000..4e1874fff
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/TEA.java
@@ -0,0 +1,62 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.TEAEngine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class TEA
+{
+ private TEA()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new TEAEngine());
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("TEA", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "TEA IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = TEA.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.TEA", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.TEA", PREFIX + "$KeyGen");
+ provider.addAlgorithm("AlgorithmParameters.TEA", PREFIX + "$AlgParams");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Threefish.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Threefish.java
new file mode 100644
index 000000000..49e4d1b15
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Threefish.java
@@ -0,0 +1,120 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.ThreefishEngine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Threefish
+{
+ private Threefish()
+ {
+ }
+
+ public static class ECB_256
+ extends BaseBlockCipher
+ {
+ public ECB_256()
+ {
+ super(new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256));
+ }
+ }
+
+ public static class ECB_512
+ extends BaseBlockCipher
+ {
+ public ECB_512()
+ {
+ super(new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512));
+ }
+ }
+
+ public static class ECB_1024
+ extends BaseBlockCipher
+ {
+ public ECB_1024()
+ {
+ super(new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024));
+ }
+ }
+
+ public static class KeyGen_256
+ extends BaseKeyGenerator
+ {
+ public KeyGen_256()
+ {
+ super("Threefish-256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGen_512
+ extends BaseKeyGenerator
+ {
+ public KeyGen_512()
+ {
+ super("Threefish-512", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class KeyGen_1024
+ extends BaseKeyGenerator
+ {
+ public KeyGen_1024()
+ {
+ super("Threefish-1024", 1024, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParams_256
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Threefish-256 IV";
+ }
+ }
+
+ public static class AlgParams_512
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Threefish-512 IV";
+ }
+ }
+
+ public static class AlgParams_1024
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Threefish-1024 IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Threefish.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.Threefish-256", PREFIX + "$ECB_256");
+ provider.addAlgorithm("Cipher.Threefish-512", PREFIX + "$ECB_512");
+ provider.addAlgorithm("Cipher.Threefish-1024", PREFIX + "$ECB_1024");
+ provider.addAlgorithm("KeyGenerator.Threefish-256", PREFIX + "$KeyGen_256");
+ provider.addAlgorithm("KeyGenerator.Threefish-512", PREFIX + "$KeyGen_512");
+ provider.addAlgorithm("KeyGenerator.Threefish-1024", PREFIX + "$KeyGen_1024");
+ provider.addAlgorithm("AlgorithmParameters.Threefish-256", PREFIX + "$AlgParams_256");
+ provider.addAlgorithm("AlgorithmParameters.Threefish-512", PREFIX + "$AlgParams_512");
+ provider.addAlgorithm("AlgorithmParameters.Threefish-1024", PREFIX + "$AlgParams_1024");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Twofish.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Twofish.java
new file mode 100644
index 000000000..ec357fe48
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/Twofish.java
@@ -0,0 +1,132 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.TwofishEngine;
+import org.spongycastle.crypto.generators.Poly1305KeyGenerator;
+import org.spongycastle.crypto.macs.GMac;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
+
+public final class Twofish
+{
+ private Twofish()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlockCipherProvider()
+ {
+ public BlockCipher get()
+ {
+ return new TwofishEngine();
+ }
+ });
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Twofish", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new TwofishEngine())));
+ }
+ }
+
+ public static class Poly1305
+ extends BaseMac
+ {
+ public Poly1305()
+ {
+ super(new org.spongycastle.crypto.macs.Poly1305(new TwofishEngine()));
+ }
+ }
+
+ public static class Poly1305KeyGen
+ extends BaseKeyGenerator
+ {
+ public Poly1305KeyGen()
+ {
+ super("Poly1305-Twofish", 256, new Poly1305KeyGenerator());
+ }
+ }
+
+ /**
+ * PBEWithSHAAndTwofish-CBC
+ */
+ static public class PBEWithSHAKeyFactory
+ extends PBESecretKeyFactory
+ {
+ public PBEWithSHAKeyFactory()
+ {
+ super("PBEwithSHAandTwofish-CBC", null, true, PKCS12, SHA1, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHAAndTwofish-CBC
+ */
+ static public class PBEWithSHA
+ extends BaseBlockCipher
+ {
+ public PBEWithSHA()
+ {
+ super(new CBCBlockCipher(new TwofishEngine()));
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Twofish IV";
+ }
+ }
+
+ public static class Mappings
+ extends SymmetricAlgorithmProvider
+ {
+ private static final String PREFIX = Twofish.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.Twofish", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.Twofish", PREFIX + "$KeyGen");
+ provider.addAlgorithm("AlgorithmParameters.Twofish", PREFIX + "$AlgParams");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH", "PKCS12PBE");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
+ provider.addAlgorithm("Cipher.PBEWITHSHAANDTWOFISH-CBC", PREFIX + "$PBEWithSHA");
+ provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", PREFIX + "$PBEWithSHAKeyFactory");
+
+ addGMacAlgorithm(provider, "Twofish", PREFIX + "$GMAC", PREFIX + "$KeyGen");
+ addPoly1305Algorithm(provider, "Twofish", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/VMPC.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/VMPC.java
new file mode 100644
index 000000000..c907d0f0a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/VMPC.java
@@ -0,0 +1,65 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.VMPCEngine;
+import org.spongycastle.crypto.macs.VMPCMac;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseMac;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class VMPC
+{
+ private VMPC()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new VMPCEngine(), 16);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("VMPC", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mac
+ extends BaseMac
+ {
+ public Mac()
+ {
+ super(new VMPCMac());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = VMPC.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.VMPC", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.VMPC", PREFIX + "$KeyGen");
+ provider.addAlgorithm("Mac.VMPCMAC", PREFIX + "$Mac");
+ provider.addAlgorithm("Alg.Alias.Mac.VMPC", "VMPCMAC");
+ provider.addAlgorithm("Alg.Alias.Mac.VMPC-MAC", "VMPCMAC");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/VMPCKSA3.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/VMPCKSA3.java
new file mode 100644
index 000000000..0132feede
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/VMPCKSA3.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.VMPCKSA3Engine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class VMPCKSA3
+{
+ private VMPCKSA3()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new VMPCKSA3Engine(), 16);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("VMPC-KSA3", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = VMPCKSA3.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.VMPC-KSA3", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.VMPC-KSA3", PREFIX + "$KeyGen");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/XSalsa20.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/XSalsa20.java
new file mode 100644
index 000000000..a99120578
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/XSalsa20.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.XSalsa20Engine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class XSalsa20
+{
+ private XSalsa20()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new XSalsa20Engine(), 24);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("XSalsa20", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = XSalsa20.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.XSALSA20", PREFIX + "$Base");
+ provider.addAlgorithm("KeyGenerator.XSALSA20", PREFIX + "$KeyGen");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/XTEA.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/XTEA.java
new file mode 100644
index 000000000..55b2b35ae
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/XTEA.java
@@ -0,0 +1,62 @@
+package org.spongycastle.jcajce.provider.symmetric;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.engines.XTEAEngine;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.spongycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.spongycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class XTEA
+{
+ private XTEA()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new XTEAEngine());
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("XTEA", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "XTEA IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = XTEA.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.XTEA", PREFIX + "$ECB");
+ provider.addAlgorithm("KeyGenerator.XTEA", PREFIX + "$KeyGen");
+ provider.addAlgorithm("AlgorithmParameters.XTEA", PREFIX + "$AlgParams");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BCPBEKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BCPBEKey.java
new file mode 100644
index 000000000..e8eac7e1f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BCPBEKey.java
@@ -0,0 +1,155 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+
+public class BCPBEKey
+ implements PBEKey
+{
+ String algorithm;
+ ASN1ObjectIdentifier oid;
+ int type;
+ int digest;
+ int keySize;
+ int ivSize;
+ CipherParameters param;
+ PBEKeySpec pbeKeySpec;
+ boolean tryWrong = false;
+
+ /**
+ * @param param
+ */
+ public BCPBEKey(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ int type,
+ int digest,
+ int keySize,
+ int ivSize,
+ PBEKeySpec pbeKeySpec,
+ CipherParameters param)
+ {
+ this.algorithm = algorithm;
+ this.oid = oid;
+ this.type = type;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ this.pbeKeySpec = pbeKeySpec;
+ this.param = param;
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "RAW";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (param != null)
+ {
+ KeyParameter kParam;
+
+ if (param instanceof ParametersWithIV)
+ {
+ kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ kParam = (KeyParameter)param;
+ }
+
+ return kParam.getKey();
+ }
+ else
+ {
+ if (type == PBE.PKCS12)
+ {
+ return PBEParametersGenerator.PKCS12PasswordToBytes(pbeKeySpec.getPassword());
+ }
+ else if (type == PBE.PKCS5S2_UTF8)
+ {
+ return PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(pbeKeySpec.getPassword());
+ }
+ else
+ {
+ return PBEParametersGenerator.PKCS5PasswordToBytes(pbeKeySpec.getPassword());
+ }
+ }
+ }
+
+ int getType()
+ {
+ return type;
+ }
+
+ int getDigest()
+ {
+ return digest;
+ }
+
+ int getKeySize()
+ {
+ return keySize;
+ }
+
+ public int getIvSize()
+ {
+ return ivSize;
+ }
+
+ public CipherParameters getParam()
+ {
+ return param;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.interfaces.PBEKey#getPassword()
+ */
+ public char[] getPassword()
+ {
+ return pbeKeySpec.getPassword();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.interfaces.PBEKey#getSalt()
+ */
+ public byte[] getSalt()
+ {
+ return pbeKeySpec.getSalt();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.interfaces.PBEKey#getIterationCount()
+ */
+ public int getIterationCount()
+ {
+ return pbeKeySpec.getIterationCount();
+ }
+
+ public ASN1ObjectIdentifier getOID()
+ {
+ return oid;
+ }
+
+ public void setTryWrongPKCS12Zero(boolean tryWrong)
+ {
+ this.tryWrong = tryWrong;
+ }
+
+ boolean shouldTryWrongPKCS12()
+ {
+ return tryWrong;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
new file mode 100644
index 000000000..532c88ce6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
@@ -0,0 +1,19 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.SecureRandom;
+
+public abstract class BaseAlgorithmParameterGenerator
+ extends AlgorithmParameterGeneratorSpi
+{
+ protected SecureRandom random;
+ protected int strength = 1024;
+
+ protected void engineInit(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
new file mode 100644
index 000000000..2bba41f1a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
@@ -0,0 +1,29 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+public abstract class BaseAlgorithmParameters
+ extends AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
new file mode 100644
index 000000000..9a3bf722a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -0,0 +1,1037 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+
+import org.spongycastle.asn1.cms.GCMParameters;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DataLengthException;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.OutputLengthException;
+import org.spongycastle.crypto.modes.AEADBlockCipher;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.CCMBlockCipher;
+import org.spongycastle.crypto.modes.CFBBlockCipher;
+import org.spongycastle.crypto.modes.CTSBlockCipher;
+import org.spongycastle.crypto.modes.EAXBlockCipher;
+import org.spongycastle.crypto.modes.GCFBBlockCipher;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.crypto.modes.GOFBBlockCipher;
+import org.spongycastle.crypto.modes.OCBBlockCipher;
+import org.spongycastle.crypto.modes.OFBBlockCipher;
+import org.spongycastle.crypto.modes.OpenPGPCFBBlockCipher;
+import org.spongycastle.crypto.modes.PGPCFBBlockCipher;
+import org.spongycastle.crypto.modes.SICBlockCipher;
+import org.spongycastle.crypto.paddings.BlockCipherPadding;
+import org.spongycastle.crypto.paddings.ISO10126d2Padding;
+import org.spongycastle.crypto.paddings.ISO7816d4Padding;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.crypto.paddings.TBCPadding;
+import org.spongycastle.crypto.paddings.X923Padding;
+import org.spongycastle.crypto.paddings.ZeroBytePadding;
+import org.spongycastle.crypto.params.AEADParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.params.ParametersWithSBox;
+import org.spongycastle.crypto.params.RC2Parameters;
+import org.spongycastle.crypto.params.RC5Parameters;
+import org.spongycastle.jcajce.spec.GOST28147ParameterSpec;
+import org.spongycastle.jcajce.spec.RepeatedSecretKeySpec;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class BaseBlockCipher
+ extends BaseWrapCipher
+ implements PBE
+{
+ private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
+
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ RC2ParameterSpec.class,
+ RC5ParameterSpec.class,
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ GOST28147ParameterSpec.class,
+ gcmSpecClass
+ };
+
+ private BlockCipher baseEngine;
+ private BlockCipherProvider engineProvider;
+ private GenericBlockCipher cipher;
+ private ParametersWithIV ivParam;
+ private AEADParameters aeadParams;
+
+ private int ivLength = 0;
+
+ private boolean padded;
+
+ private PBEParameterSpec pbeSpec = null;
+ private String pbeAlgorithm = null;
+
+ private String modeName = null;
+
+ private static Class lookup(String className)
+ {
+ try
+ {
+ Class def = BaseBlockCipher.class.getClassLoader().loadClass(className);
+
+ return def;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ protected BaseBlockCipher(
+ BlockCipher engine)
+ {
+ baseEngine = engine;
+
+ cipher = new BufferedGenericBlockCipher(engine);
+ }
+
+ protected BaseBlockCipher(
+ BlockCipherProvider provider)
+ {
+ baseEngine = provider.get();
+ engineProvider = provider;
+
+ cipher = new BufferedGenericBlockCipher(provider.get());
+ }
+
+ protected BaseBlockCipher(
+ AEADBlockCipher engine)
+ {
+ baseEngine = engine.getUnderlyingCipher();
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(engine);
+ }
+
+ protected BaseBlockCipher(
+ org.spongycastle.crypto.BlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine;
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected BaseBlockCipher(
+ BufferedBlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine.getUnderlyingCipher();
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return baseEngine.getBlockSize();
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return (ivParam != null) ? ivParam.getIV() : null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length * 8;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return cipher.getOutputSize(inputLen);
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (pbeSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(pbeSpec);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ else if (ivParam != null)
+ {
+ String name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+ if (name.indexOf('/') >= 0)
+ {
+ name = name.substring(0, name.indexOf('/'));
+ }
+
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(ivParam.getIV());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ else if (aeadParams != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("GCM", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize()).getEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ modeName = Strings.toUpperCase(mode);
+
+ if (modeName.equals("ECB"))
+ {
+ ivLength = 0;
+ cipher = new BufferedGenericBlockCipher(baseEngine);
+ }
+ else if (modeName.equals("CBC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(
+ new CBCBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("OFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("CFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("PGP"))
+ {
+ boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
+
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(
+ new PGPCFBBlockCipher(baseEngine, inlineIV));
+ }
+ else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+ {
+ ivLength = 0;
+ cipher = new BufferedGenericBlockCipher(
+ new OpenPGPCFBBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("SIC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (ivLength < 16)
+ {
+ throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+ }
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CTR"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("GOFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new GOFBBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("GCFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new GCFBBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CTS"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CCM"))
+ {
+ ivLength = 13; // CCM nonce 7..13 bytes
+ cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("OCB"))
+ {
+ if (engineProvider != null)
+ {
+ // Nonce restricted to max 120 bits over 128 bit block cipher since draft-irtf-cfrg-ocb-03
+ ivLength = 15;
+ cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
+ }
+ else
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+ }
+ else if (modeName.startsWith("EAX"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("GCM"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine));
+ }
+ else
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String paddingName = Strings.toUpperCase(padding);
+
+ if (paddingName.equals("NOPADDING"))
+ {
+ if (cipher.wrapOnNoPadding())
+ {
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ }
+ else if (paddingName.equals("WITHCTS"))
+ {
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ else
+ {
+ padded = true;
+
+ if (isAEADModeName(modeName))
+ {
+ throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes.");
+ }
+ else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else if (paddingName.equals("ZEROBYTEPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
+ }
+ else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
+ }
+ else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
+ }
+ else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
+ }
+ else if (paddingName.equals("TBCPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
+ }
+ else
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ this.pbeSpec = null;
+ this.pbeAlgorithm = null;
+ this.engineParams = null;
+ this.aeadParams = null;
+
+ //
+ // basic key check
+ //
+ if (!(key instanceof SecretKey))
+ {
+ throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+ }
+
+ //
+ // for RC5-64 we must have some default parameters
+ //
+ if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
+ {
+ throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
+ }
+
+ //
+ // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+ //
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (k.getOID() != null)
+ {
+ pbeAlgorithm = k.getOID().getId();
+ }
+ else
+ {
+ pbeAlgorithm = k.getAlgorithm();
+ }
+
+ if (k.getParam() != null)
+ {
+ param = k.getParam();
+ if (params instanceof IvParameterSpec)
+ {
+ IvParameterSpec iv = (IvParameterSpec)params;
+
+ param = new ParametersWithIV(param, iv.getIV());
+ }
+ else if (params instanceof GOST28147ParameterSpec)
+ {
+ // need to pick up IV and SBox.
+ GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+
+ param = new ParametersWithSBox(param, gost28147Param.getSbox());
+
+ if (gost28147Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, gost28147Param.getIV());
+ }
+ }
+ }
+ else if (params instanceof PBEParameterSpec)
+ {
+ pbeSpec = (PBEParameterSpec)params;
+ param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+
+ if (param instanceof ParametersWithIV)
+ {
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ if (ivLength != 0)
+ {
+ IvParameterSpec p = (IvParameterSpec)params;
+
+ if (p.getIV().length != ivLength && !isAEADModeName(modeName))
+ {
+ throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+ }
+
+ if (key instanceof RepeatedSecretKeySpec)
+ {
+ param = new ParametersWithIV(null, p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else
+ {
+ if (modeName != null && modeName.equals("ECB"))
+ {
+ throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
+ }
+
+ param = new KeyParameter(key.getEncoded());
+ }
+ }
+ else if (params instanceof GOST28147ParameterSpec)
+ {
+ GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+
+ param = new ParametersWithSBox(
+ new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+
+ if (gost28147Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, gost28147Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params instanceof RC2ParameterSpec)
+ {
+ RC2ParameterSpec rc2Param = (RC2ParameterSpec)params;
+
+ param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+
+ if (rc2Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, rc2Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params instanceof RC5ParameterSpec)
+ {
+ RC5ParameterSpec rc5Param = (RC5ParameterSpec)params;
+
+ param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+ if (baseEngine.getAlgorithmName().startsWith("RC5"))
+ {
+ if (baseEngine.getAlgorithmName().equals("RC5-32"))
+ {
+ if (rc5Param.getWordSize() != 32)
+ {
+ throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+ }
+ }
+ else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+ {
+ if (rc5Param.getWordSize() != 64)
+ {
+ throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+ }
+ }
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+ }
+ if ((rc5Param.getIV() != null) && (ivLength != 0))
+ {
+ param = new ParametersWithIV(param, rc5Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (gcmSpecClass != null && gcmSpecClass.isInstance(params))
+ {
+ if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
+ {
+ throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes.");
+ }
+
+ try
+ {
+ Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+ Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+ if (key instanceof RepeatedSecretKeySpec)
+ {
+ param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+ }
+ else
+ {
+ param = aeadParams = new AEADParameters(new KeyParameter(key.getEncoded()), ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
+ }
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ }
+
+ if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters))
+ {
+ SecureRandom ivRandom = random;
+
+ if (ivRandom == null)
+ {
+ ivRandom = new SecureRandom();
+ }
+
+ if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+ {
+ byte[] iv = new byte[ivLength];
+
+ ivRandom.nextBytes(iv);
+ param = new ParametersWithIV(param, iv);
+ ivParam = (ParametersWithIV)param;
+ }
+ else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
+ {
+ throw new InvalidAlgorithmParameterException("no IV set when one expected");
+ }
+ }
+
+ if (random != null && padded)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ try
+ {
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ for (int i = 0; i != availableSpecs.length; i++)
+ {
+ if (availableSpecs[i] == null)
+ {
+ continue;
+ }
+
+ try
+ {
+ paramSpec = params.getParameterSpec(availableSpecs[i]);
+ break;
+ }
+ catch (Exception e)
+ {
+ // try again if possible
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineInit(opmode, key, paramSpec, random);
+
+ engineParams = 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());
+ }
+ }
+
+ protected void engineUpdateAAD(byte[] input, int offset, int length)
+ {
+ cipher.updateAAD(input, offset, length);
+ }
+
+ protected void engineUpdateAAD(ByteBuffer bytebuffer)
+ {
+ int offset = bytebuffer.arrayOffset() + bytebuffer.position();
+ int length = bytebuffer.limit() - bytebuffer.position();
+ engineUpdateAAD(bytebuffer.array(), offset, length);
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ int length = cipher.getUpdateOutputSize(inputLen);
+
+ if (length > 0)
+ {
+ byte[] out = new byte[length];
+
+ int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+ if (len == 0)
+ {
+ return null;
+ }
+ else if (len != out.length)
+ {
+ byte[] tmp = new byte[len];
+
+ System.arraycopy(out, 0, tmp, 0, len);
+
+ return tmp;
+ }
+
+ return out;
+ }
+
+ cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ try
+ {
+ return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+ catch (DataLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ int len = 0;
+ byte[] tmp = new byte[engineGetOutputSize(inputLen)];
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+ }
+
+ try
+ {
+ len += cipher.doFinal(tmp, len);
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ if (len == tmp.length)
+ {
+ return tmp;
+ }
+
+ byte[] out = new byte[len];
+
+ System.arraycopy(tmp, 0, out, 0, len);
+
+ return out;
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+ {
+ try
+ {
+ int len = 0;
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ return (len + cipher.doFinal(output, outputOffset + len));
+ }
+ catch (OutputLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ private boolean isAEADModeName(
+ String modeName)
+ {
+ return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName) || "OCB".equals(modeName);
+ }
+
+ /*
+ * The ciphers that inherit from us.
+ */
+
+ static private interface GenericBlockCipher
+ {
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ public boolean wrapOnNoPadding();
+
+ public String getAlgorithmName();
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher();
+
+ public int getOutputSize(int len);
+
+ public int getUpdateOutputSize(int len);
+
+ public void updateAAD(byte[] input, int offset, int length);
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException;
+ }
+
+ private static class BufferedGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private BufferedBlockCipher cipher;
+
+ BufferedGenericBlockCipher(BufferedBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ BufferedGenericBlockCipher(org.spongycastle.crypto.BlockCipher cipher)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher);
+ }
+
+ BufferedGenericBlockCipher(org.spongycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher, padding);
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return !(cipher instanceof CTSBlockCipher);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public void updateAAD(byte[] input, int offset, int length)
+ {
+ throw new UnsupportedOperationException("AAD is not supported in the current mode.");
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+
+ private static class AEADGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private AEADBlockCipher cipher;
+
+ AEADGenericBlockCipher(AEADBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return false;
+ }
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public void updateAAD(byte[] input, int offset, int length)
+ {
+ cipher.processAADBytes(input, offset, length);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
new file mode 100644
index 000000000..460d14a96
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
@@ -0,0 +1,82 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyGeneratorSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.crypto.CipherKeyGenerator;
+import org.spongycastle.crypto.KeyGenerationParameters;
+
+public class BaseKeyGenerator
+ extends KeyGeneratorSpi
+{
+ protected String algName;
+ protected int keySize;
+ protected int defaultKeySize;
+ protected CipherKeyGenerator engine;
+
+ protected boolean uninitialised = true;
+
+ protected BaseKeyGenerator(
+ String algName,
+ int defaultKeySize,
+ CipherKeyGenerator engine)
+ {
+ this.algName = algName;
+ this.keySize = this.defaultKeySize = defaultKeySize;
+ this.engine = engine;
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("Not Implemented");
+ }
+
+ protected void engineInit(
+ SecureRandom random)
+ {
+ if (random != null)
+ {
+ engine.init(new KeyGenerationParameters(random, defaultKeySize));
+ uninitialised = false;
+ }
+ }
+
+ protected void engineInit(
+ int keySize,
+ SecureRandom random)
+ {
+ try
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+ engine.init(new KeyGenerationParameters(random, keySize));
+ uninitialised = false;
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new InvalidParameterException(e.getMessage());
+ }
+ }
+
+ protected SecretKey engineGenerateKey()
+ {
+ if (uninitialised)
+ {
+ engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+ uninitialised = false;
+ }
+
+ return new SecretKeySpec(engine.generateKey(), algName);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseMac.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseMac.java
new file mode 100644
index 000000000..a711dae72
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseMac.java
@@ -0,0 +1,144 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.crypto.MacSpi;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Mac;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.crypto.params.SkeinParameters;
+import org.spongycastle.jcajce.spec.SkeinParameterSpec;
+
+public class BaseMac
+ extends MacSpi implements PBE
+{
+ private Mac macEngine;
+
+ private int pbeType = PKCS12;
+ private int pbeHash = SHA1;
+ private int keySize = 160;
+
+ protected BaseMac(
+ Mac macEngine)
+ {
+ this.macEngine = macEngine;
+ }
+
+ protected BaseMac(
+ Mac macEngine,
+ int pbeType,
+ int pbeHash,
+ int keySize)
+ {
+ this.macEngine = macEngine;
+ this.pbeType = pbeType;
+ this.pbeHash = pbeHash;
+ this.keySize = keySize;
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (key == null)
+ {
+ throw new InvalidKeyException("key is null");
+ }
+
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (k.getParam() != null)
+ {
+ param = k.getParam();
+ }
+ else if (params instanceof PBEParameterSpec)
+ {
+ param = PBE.Util.makePBEMacParameters(k, params);
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+ }
+ else if (params instanceof SkeinParameterSpec)
+ {
+ param = new SkeinParameters.Builder(copyMap(((SkeinParameterSpec)params).getParameters())).setKey(key.getEncoded()).build();
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ }
+
+ macEngine.init(param);
+ }
+
+ protected int engineGetMacLength()
+ {
+ return macEngine.getMacSize();
+ }
+
+ protected void engineReset()
+ {
+ macEngine.reset();
+ }
+
+ protected void engineUpdate(
+ byte input)
+ {
+ macEngine.update(input);
+ }
+
+ protected void engineUpdate(
+ byte[] input,
+ int offset,
+ int len)
+ {
+ macEngine.update(input, offset, len);
+ }
+
+ protected byte[] engineDoFinal()
+ {
+ byte[] out = new byte[engineGetMacLength()];
+
+ macEngine.doFinal(out, 0);
+
+ return out;
+ }
+
+ private static Hashtable copyMap(Map paramsMap)
+ {
+ Hashtable newTable = new Hashtable();
+
+ Iterator keys = paramsMap.keySet().iterator();
+ while (keys.hasNext())
+ {
+ Object key = keys.next();
+ newTable.put(key, paramsMap.get(key));
+ }
+
+ return newTable;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
new file mode 100644
index 000000000..1ce00a3c7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
@@ -0,0 +1,93 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Constructor;
+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;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+
+public class BaseSecretKeyFactory
+ extends SecretKeyFactorySpi
+ implements PBE
+{
+ protected String algName;
+ protected ASN1ObjectIdentifier algOid;
+
+ protected BaseSecretKeyFactory(
+ String algName,
+ ASN1ObjectIdentifier algOid)
+ {
+ this.algName = algName;
+ this.algOid = algOid;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof SecretKeySpec)
+ {
+ return (SecretKey)keySpec;
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ try
+ {
+ Class[] parameters = { byte[].class };
+
+ Constructor c = keySpec.getConstructor(parameters);
+ Object[] p = new Object[1];
+
+ p[0] = key.getEncoded();
+
+ return (KeySpec)c.newInstance(p);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ protected SecretKey engineTranslateKey(
+ SecretKey key)
+ throws InvalidKeyException
+ {
+ if (key == null)
+ {
+ throw new InvalidKeyException("key parameter is null");
+ }
+
+ if (!key.getAlgorithm().equalsIgnoreCase(algName))
+ {
+ throw new InvalidKeyException("Key not of type " + algName + ".");
+ }
+
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
new file mode 100644
index 000000000..92027555c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
@@ -0,0 +1,370 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DataLengthException;
+import org.spongycastle.crypto.StreamBlockCipher;
+import org.spongycastle.crypto.StreamCipher;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class BaseStreamCipher
+ extends BaseWrapCipher
+ implements PBE
+{
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ RC2ParameterSpec.class,
+ RC5ParameterSpec.class,
+ IvParameterSpec.class,
+ PBEParameterSpec.class
+ };
+
+ private StreamCipher cipher;
+ private ParametersWithIV ivParam;
+
+ private int ivLength = 0;
+
+ private PBEParameterSpec pbeSpec = null;
+ private String pbeAlgorithm = null;
+
+ protected BaseStreamCipher(
+ StreamCipher engine,
+ int ivLength)
+ {
+ cipher = engine;
+ this.ivLength = ivLength;
+ }
+
+ protected BaseStreamCipher(
+ BlockCipher engine,
+ int ivLength)
+ {
+ this.ivLength = ivLength;
+
+ cipher = new StreamBlockCipher(engine);
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return 0;
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return (ivParam != null) ? ivParam.getIV() : null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length * 8;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return inputLen;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (pbeSpec != null)
+ {
+ try
+ {
+ AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(pbeSpec);
+
+ return engineParams;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ /**
+ * should never be called.
+ */
+ protected void engineSetMode(
+ String mode)
+ {
+ if (!mode.equalsIgnoreCase("ECB"))
+ {
+ throw new IllegalArgumentException("can't support mode " + mode);
+ }
+ }
+
+ /**
+ * should never be called.
+ */
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ if (!padding.equalsIgnoreCase("NoPadding"))
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ this.pbeSpec = null;
+ this.pbeAlgorithm = null;
+
+ this.engineParams = null;
+
+ //
+ // basic key check
+ //
+ if (!(key instanceof SecretKey))
+ {
+ throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+ }
+
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (k.getOID() != null)
+ {
+ pbeAlgorithm = k.getOID().getId();
+ }
+ else
+ {
+ pbeAlgorithm = k.getAlgorithm();
+ }
+
+ if (k.getParam() != null)
+ {
+ param = k.getParam();
+ pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
+ }
+ else if (params instanceof PBEParameterSpec)
+ {
+ param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName());
+ pbeSpec = (PBEParameterSpec)params;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+
+ if (k.getIvSize() != 0)
+ {
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ }
+
+ if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+ {
+ SecureRandom ivRandom = random;
+
+ if (ivRandom == null)
+ {
+ ivRandom = new SecureRandom();
+ }
+
+ if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+ {
+ byte[] iv = new byte[ivLength];
+
+ ivRandom.nextBytes(iv);
+ param = new ParametersWithIV(param, iv);
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("no IV set when one expected");
+ }
+ }
+
+ try
+ {
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ for (int i = 0; i != availableSpecs.length; i++)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(availableSpecs[i]);
+ break;
+ }
+ catch (Exception e)
+ {
+ continue;
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineInit(opmode, key, paramSpec, random);
+ engineParams = 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());
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ byte[] out = new byte[inputLen];
+
+ cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+ return out;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ try
+ {
+ cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+
+ return inputLen;
+ }
+ catch (DataLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ if (inputLen != 0)
+ {
+ byte[] out = engineUpdate(input, inputOffset, inputLen);
+
+ cipher.reset();
+
+ return out;
+ }
+
+ cipher.reset();
+
+ return new byte[0];
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ if (inputLen != 0)
+ {
+ cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ cipher.reset();
+
+ return inputLen;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
new file mode 100644
index 000000000..39f4bb027
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
@@ -0,0 +1,388 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+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.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+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.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.Wrapper;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public abstract class BaseWrapCipher
+ extends CipherSpi
+ implements PBE
+{
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ RC2ParameterSpec.class,
+ RC5ParameterSpec.class
+ };
+
+ protected int pbeType = PKCS12;
+ protected int pbeHash = SHA1;
+ protected int pbeKeySize;
+ protected int pbeIvSize;
+
+ protected AlgorithmParameters engineParams = null;
+
+ protected Wrapper wrapEngine = null;
+
+ private int ivSize;
+ private byte[] iv;
+
+ protected BaseWrapCipher()
+ {
+ }
+
+ protected BaseWrapCipher(
+ Wrapper wrapEngine)
+ {
+ this(wrapEngine, 0);
+ }
+
+ protected BaseWrapCipher(
+ Wrapper wrapEngine,
+ int ivSize)
+ {
+ this.wrapEngine = wrapEngine;
+ this.ivSize = ivSize;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return 0;
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return (byte[])iv.clone();
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return -1;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return null;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (params instanceof PBEParameterSpec)
+ {
+ param = PBE.Util.makePBEParameters(k, params, wrapEngine.getAlgorithmName());
+ }
+ else if (k.getParam() != null)
+ {
+ param = k.getParam();
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+ }
+ else
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+
+ if (params instanceof IvParameterSpec)
+ {
+ IvParameterSpec iv = (IvParameterSpec) params;
+ param = new ParametersWithIV(param, iv.getIV());
+ }
+
+ if (param instanceof KeyParameter && ivSize != 0)
+ {
+ iv = new byte[ivSize];
+ random.nextBytes(iv);
+ param = new ParametersWithIV(param, iv);
+ }
+
+ switch (opmode)
+ {
+ case Cipher.WRAP_MODE:
+ wrapEngine.init(true, param);
+ break;
+ case Cipher.UNWRAP_MODE:
+ wrapEngine.init(false, param);
+ break;
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.DECRYPT_MODE:
+ throw new IllegalArgumentException("engine only valid for wrapping");
+ default:
+ System.out.println("eeek!");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ for (int i = 0; i != availableSpecs.length; i++)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(availableSpecs[i]);
+ break;
+ }
+ catch (Exception e)
+ {
+ // try next spec
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineParams = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ throw new RuntimeException("not supported for wrapping");
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ throw new RuntimeException("not supported for wrapping");
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ return null;
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+ {
+ return 0;
+ }
+
+ protected byte[] engineWrap(
+ Key key)
+ throws IllegalBlockSizeException, InvalidKeyException
+ {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null)
+ {
+ throw new InvalidKeyException("Cannot wrap key, null encoding.");
+ }
+
+ try
+ {
+ if (wrapEngine == null)
+ {
+ return engineDoFinal(encoded, 0, encoded.length);
+ }
+ else
+ {
+ return wrapEngine.wrap(encoded, 0, encoded.length);
+ }
+ }
+ catch (BadPaddingException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ }
+
+ protected Key engineUnwrap(
+ byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException, NoSuchAlgorithmException
+ {
+ byte[] encoded;
+ try
+ {
+ if (wrapEngine == null)
+ {
+ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ }
+ else
+ {
+ encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ catch (BadPaddingException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ catch (IllegalBlockSizeException e2)
+ {
+ throw new InvalidKeyException(e2.getMessage());
+ }
+
+ if (wrappedKeyType == Cipher.SECRET_KEY)
+ {
+ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+ }
+ else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ /*
+ * The caller doesn't know the algorithm as it is part of
+ * the encrypted data.
+ */
+ try
+ {
+ PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);
+
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+ if (privKey != null)
+ {
+ return privKey;
+ }
+ else
+ {
+ throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("Invalid key encoding.");
+ }
+ }
+ else
+ {
+ try
+ {
+ KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+ if (wrappedKeyType == Cipher.PUBLIC_KEY)
+ {
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ }
+ else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (InvalidKeySpecException e2)
+ {
+ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+ }
+
+ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+ }
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BlockCipherProvider.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BlockCipherProvider.java
new file mode 100644
index 000000000..b4a55c10e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/BlockCipherProvider.java
@@ -0,0 +1,8 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import org.spongycastle.crypto.BlockCipher;
+
+public interface BlockCipherProvider
+{
+ BlockCipher get();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
new file mode 100644
index 000000000..1c1ae1892
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
@@ -0,0 +1,118 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.util.Arrays;
+
+public class IvAlgorithmParameters
+ extends BaseAlgorithmParameters
+{
+ private byte[] iv;
+
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ return engineGetEncoded("ASN.1");
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format))
+ {
+ return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
+ }
+
+ if (format.equals("RAW"))
+ {
+ return Arrays.clone(iv);
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof IvParameterSpec))
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+ }
+
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ //
+ // check that we don't have a DER encoded octet string
+ //
+ if ((params.length % 8) != 0
+ && params[0] == 0x04 && params[1] == params.length - 2)
+ {
+ ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(params);
+
+ params = oct.getOctets();
+ }
+
+ this.iv = Arrays.clone(params);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format))
+ {
+ try
+ {
+ ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(params);
+
+ engineInit(oct.getOctets());
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Exception decoding: " + e);
+ }
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "IV Parameters";
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/PBE.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/PBE.java
new file mode 100644
index 000000000..a0a4721e8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/PBE.java
@@ -0,0 +1,319 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.digests.MD2Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.TigerDigest;
+import org.spongycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS5S1ParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.spongycastle.crypto.params.DESParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+
+public interface PBE
+{
+ //
+ // PBE Based encryption constants - by default we do PKCS12 with SHA-1
+ //
+ static final int MD5 = 0;
+ static final int SHA1 = 1;
+ static final int RIPEMD160 = 2;
+ static final int TIGER = 3;
+ static final int SHA256 = 4;
+ static final int MD2 = 5;
+ static final int GOST3411 = 6;
+
+ static final int PKCS5S1 = 0;
+ static final int PKCS5S2 = 1;
+ static final int PKCS12 = 2;
+ static final int OPENSSL = 3;
+ static final int PKCS5S1_UTF8 = 4;
+ static final int PKCS5S2_UTF8 = 5;
+
+ /**
+ * uses the appropriate mixer to generate the key and IV if necessary.
+ */
+ static class Util
+ {
+ static private PBEParametersGenerator makePBEGenerator(
+ int type,
+ int hash)
+ {
+ PBEParametersGenerator generator;
+
+ if (type == PKCS5S1 || type == PKCS5S1_UTF8)
+ {
+ switch (hash)
+ {
+ case MD2:
+ generator = new PKCS5S1ParametersGenerator(new MD2Digest());
+ break;
+ case MD5:
+ generator = new PKCS5S1ParametersGenerator(new MD5Digest());
+ break;
+ case SHA1:
+ generator = new PKCS5S1ParametersGenerator(new SHA1Digest());
+ break;
+ default:
+ throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1.");
+ }
+ }
+ else if (type == PKCS5S2 || type == PKCS5S2_UTF8)
+ {
+ switch (hash)
+ {
+ case MD2:
+ generator = new PKCS5S2ParametersGenerator(new MD2Digest());
+ break;
+ case MD5:
+ generator = new PKCS5S2ParametersGenerator(new MD5Digest());
+ break;
+ case SHA1:
+ generator = new PKCS5S2ParametersGenerator(new SHA1Digest());
+ break;
+ case RIPEMD160:
+ generator = new PKCS5S2ParametersGenerator(new RIPEMD160Digest());
+ break;
+ case TIGER:
+ generator = new PKCS5S2ParametersGenerator(new TigerDigest());
+ break;
+ case SHA256:
+ generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
+ break;
+ case GOST3411:
+ generator = new PKCS5S2ParametersGenerator(new GOST3411Digest());
+ break;
+ default:
+ throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption.");
+ }
+ }
+ else if (type == PKCS12)
+ {
+ switch (hash)
+ {
+ case MD2:
+ generator = new PKCS12ParametersGenerator(new MD2Digest());
+ break;
+ case MD5:
+ generator = new PKCS12ParametersGenerator(new MD5Digest());
+ break;
+ case SHA1:
+ generator = new PKCS12ParametersGenerator(new SHA1Digest());
+ break;
+ case RIPEMD160:
+ generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
+ break;
+ case TIGER:
+ generator = new PKCS12ParametersGenerator(new TigerDigest());
+ break;
+ case SHA256:
+ generator = new PKCS12ParametersGenerator(new SHA256Digest());
+ break;
+ case GOST3411:
+ generator = new PKCS12ParametersGenerator(new GOST3411Digest());
+ break;
+ default:
+ throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+ }
+ }
+ else
+ {
+ generator = new OpenSSLPBEParametersGenerator();
+ }
+
+ return generator;
+ }
+
+ /**
+ * construct a key and iv (if necessary) suitable for use with a
+ * Cipher.
+ */
+ public static CipherParameters makePBEParameters(
+ BCPBEKey pbeKey,
+ AlgorithmParameterSpec spec,
+ String targetAlgorithm)
+ {
+ if ((spec == null) || !(spec instanceof PBEParameterSpec))
+ {
+ throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+ }
+
+ PBEParameterSpec pbeParam = (PBEParameterSpec)spec;
+ PBEParametersGenerator generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
+ byte[] key = pbeKey.getEncoded();
+ CipherParameters param;
+
+ if (pbeKey.shouldTryWrongPKCS12())
+ {
+ key = new byte[2];
+ }
+
+ generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+ if (pbeKey.getIvSize() != 0)
+ {
+ param = generator.generateDerivedParameters(pbeKey.getKeySize(), pbeKey.getIvSize());
+ }
+ else
+ {
+ param = generator.generateDerivedParameters(pbeKey.getKeySize());
+ }
+
+ if (targetAlgorithm.startsWith("DES"))
+ {
+ if (param instanceof ParametersWithIV)
+ {
+ KeyParameter kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+
+ DESParameters.setOddParity(kParam.getKey());
+ }
+ else
+ {
+ KeyParameter kParam = (KeyParameter)param;
+
+ DESParameters.setOddParity(kParam.getKey());
+ }
+ }
+
+ for (int i = 0; i != key.length; i++)
+ {
+ key[i] = 0;
+ }
+
+ return param;
+ }
+
+ /**
+ * generate a PBE based key suitable for a MAC algorithm, the
+ * key size is chosen according the MAC size, or the hashing algorithm,
+ * whichever is greater.
+ */
+ public static CipherParameters makePBEMacParameters(
+ BCPBEKey pbeKey,
+ AlgorithmParameterSpec spec)
+ {
+ if ((spec == null) || !(spec instanceof PBEParameterSpec))
+ {
+ throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+ }
+
+ PBEParameterSpec pbeParam = (PBEParameterSpec)spec;
+ PBEParametersGenerator generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
+ byte[] key = pbeKey.getEncoded();
+ CipherParameters param;
+
+ if (pbeKey.shouldTryWrongPKCS12())
+ {
+ key = new byte[2];
+ }
+
+ generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+ param = generator.generateDerivedMacParameters(pbeKey.getKeySize());
+
+ for (int i = 0; i != key.length; i++)
+ {
+ key[i] = 0;
+ }
+
+ return param;
+ }
+
+ /**
+ * construct a key and iv (if necessary) suitable for use with a
+ * Cipher.
+ */
+ public static CipherParameters makePBEParameters(
+ PBEKeySpec keySpec,
+ int type,
+ int hash,
+ int keySize,
+ int ivSize)
+ {
+ PBEParametersGenerator generator = makePBEGenerator(type, hash);
+ byte[] key;
+ CipherParameters param;
+
+ key = convertPassword(type, keySpec);
+
+ generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
+
+ if (ivSize != 0)
+ {
+ param = generator.generateDerivedParameters(keySize, ivSize);
+ }
+ else
+ {
+ param = generator.generateDerivedParameters(keySize);
+ }
+
+ for (int i = 0; i != key.length; i++)
+ {
+ key[i] = 0;
+ }
+
+ return param;
+ }
+
+
+ /**
+ * generate a PBE based key suitable for a MAC algorithm, the
+ * key size is chosen according the MAC size, or the hashing algorithm,
+ * whichever is greater.
+ */
+ public static CipherParameters makePBEMacParameters(
+ PBEKeySpec keySpec,
+ int type,
+ int hash,
+ int keySize)
+ {
+ PBEParametersGenerator generator = makePBEGenerator(type, hash);
+ byte[] key;
+ CipherParameters param;
+
+ key = convertPassword(type, keySpec);
+
+ generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
+
+ param = generator.generateDerivedMacParameters(keySize);
+
+ for (int i = 0; i != key.length; i++)
+ {
+ key[i] = 0;
+ }
+
+ return param;
+ }
+
+ private static byte[] convertPassword(int type, PBEKeySpec keySpec)
+ {
+ byte[] key;
+
+ if (type == PKCS12)
+ {
+ key = PBEParametersGenerator.PKCS12PasswordToBytes(keySpec.getPassword());
+ }
+ else if (type == PKCS5S2_UTF8 || type == PKCS5S1_UTF8)
+ {
+ key = PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(keySpec.getPassword());
+ }
+ else
+ {
+ key = PBEParametersGenerator.PKCS5PasswordToBytes(keySpec.getPassword());
+ }
+ return key;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java
new file mode 100644
index 000000000..0e4db8ec0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java
@@ -0,0 +1,68 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+
+public class PBESecretKeyFactory
+ extends BaseSecretKeyFactory
+ implements PBE
+{
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public PBESecretKeyFactory(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ if (forCipher)
+ {
+ param = PBE.Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+ }
+ else
+ {
+ param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+ }
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AlgorithmProvider.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AlgorithmProvider.java
new file mode 100644
index 000000000..678dc34f2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AlgorithmProvider.java
@@ -0,0 +1,8 @@
+package org.spongycastle.jcajce.provider.util;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+
+public abstract class AlgorithmProvider
+{
+ public abstract void configure(ConfigurableProvider provider);
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java
new file mode 100644
index 000000000..77218f47c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java
@@ -0,0 +1,42 @@
+package org.spongycastle.jcajce.provider.util;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+
+public abstract class AsymmetricAlgorithmProvider
+ extends AlgorithmProvider
+{
+ protected void addSignatureAlgorithm(
+ ConfigurableProvider provider,
+ String digest,
+ String algorithm,
+ String className,
+ ASN1ObjectIdentifier oid)
+ {
+ String mainName = digest + "WITH" + algorithm;
+ String jdk11Variation1 = digest + "with" + algorithm;
+ String jdk11Variation2 = digest + "With" + algorithm;
+ String alias = digest + "/" + algorithm;
+
+ provider.addAlgorithm("Signature." + mainName, className);
+ provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation1, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation2, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + alias, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + oid, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName);
+ }
+
+ protected void registerOid(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name, AsymmetricKeyInfoConverter keyFactory)
+ {
+ provider.addAlgorithm("Alg.Alias.KeyFactory." + oid, name);
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator." + oid, name);
+
+ provider.addKeyInfoConverter(oid, keyFactory);
+ }
+
+ protected void registerOidAlgorithmParameters(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+ {
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + oid, name);
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + oid, name);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java
new file mode 100644
index 000000000..8181dea7b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java
@@ -0,0 +1,17 @@
+package org.spongycastle.jcajce.provider.util;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public interface AsymmetricKeyInfoConverter
+{
+ PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException;
+
+ PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException;
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/DigestFactory.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/DigestFactory.java
new file mode 100644
index 000000000..ab090ac8c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/DigestFactory.java
@@ -0,0 +1,131 @@
+package org.spongycastle.jcajce.provider.util;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.util.Strings;
+
+public class DigestFactory
+{
+ private static Set md5 = new HashSet();
+ private static Set sha1 = new HashSet();
+ private static Set sha224 = new HashSet();
+ private static Set sha256 = new HashSet();
+ private static Set sha384 = new HashSet();
+ private static Set sha512 = new HashSet();
+
+ private static Map oids = new HashMap();
+
+ static
+ {
+ md5.add("MD5");
+ md5.add(PKCSObjectIdentifiers.md5.getId());
+
+ sha1.add("SHA1");
+ sha1.add("SHA-1");
+ sha1.add(OIWObjectIdentifiers.idSHA1.getId());
+
+ sha224.add("SHA224");
+ sha224.add("SHA-224");
+ sha224.add(NISTObjectIdentifiers.id_sha224.getId());
+
+ sha256.add("SHA256");
+ sha256.add("SHA-256");
+ sha256.add(NISTObjectIdentifiers.id_sha256.getId());
+
+ sha384.add("SHA384");
+ sha384.add("SHA-384");
+ sha384.add(NISTObjectIdentifiers.id_sha384.getId());
+
+ sha512.add("SHA512");
+ sha512.add("SHA-512");
+ sha512.add(NISTObjectIdentifiers.id_sha512.getId());
+
+ oids.put("MD5", PKCSObjectIdentifiers.md5);
+ oids.put(PKCSObjectIdentifiers.md5.getId(), PKCSObjectIdentifiers.md5);
+
+ oids.put("SHA1", OIWObjectIdentifiers.idSHA1);
+ oids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
+ oids.put(OIWObjectIdentifiers.idSHA1.getId(), OIWObjectIdentifiers.idSHA1);
+
+ oids.put("SHA224", NISTObjectIdentifiers.id_sha224);
+ oids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+ oids.put(NISTObjectIdentifiers.id_sha224.getId(), NISTObjectIdentifiers.id_sha224);
+
+ oids.put("SHA256", NISTObjectIdentifiers.id_sha256);
+ oids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+ oids.put(NISTObjectIdentifiers.id_sha256.getId(), NISTObjectIdentifiers.id_sha256);
+
+ oids.put("SHA384", NISTObjectIdentifiers.id_sha384);
+ oids.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+ oids.put(NISTObjectIdentifiers.id_sha384.getId(), NISTObjectIdentifiers.id_sha384);
+
+ oids.put("SHA512", NISTObjectIdentifiers.id_sha512);
+ oids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+ oids.put(NISTObjectIdentifiers.id_sha512.getId(), NISTObjectIdentifiers.id_sha512);
+ }
+
+ public static Digest getDigest(
+ String digestName)
+ {
+ digestName = Strings.toUpperCase(digestName);
+
+ if (sha1.contains(digestName))
+ {
+ return new SHA1Digest();
+ }
+ if (md5.contains(digestName))
+ {
+ return new MD5Digest();
+ }
+ if (sha224.contains(digestName))
+ {
+ return new SHA224Digest();
+ }
+ if (sha256.contains(digestName))
+ {
+ return new SHA256Digest();
+ }
+ if (sha384.contains(digestName))
+ {
+ return new SHA384Digest();
+ }
+ if (sha512.contains(digestName))
+ {
+ return new SHA512Digest();
+ }
+
+ return null;
+ }
+
+ public static boolean isSameDigest(
+ String digest1,
+ String digest2)
+ {
+ return (sha1.contains(digest1) && sha1.contains(digest2))
+ || (sha224.contains(digest1) && sha224.contains(digest2))
+ || (sha256.contains(digest1) && sha256.contains(digest2))
+ || (sha384.contains(digest1) && sha384.contains(digest2))
+ || (sha512.contains(digest1) && sha512.contains(digest2))
+ || (md5.contains(digest1) && md5.contains(digest2));
+ }
+
+ public static ASN1ObjectIdentifier getOID(
+ String digestName)
+ {
+ return (ASN1ObjectIdentifier)oids.get(digestName);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/SecretKeyUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/SecretKeyUtil.java
new file mode 100644
index 000000000..7d763a21e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/provider/util/SecretKeyUtil.java
@@ -0,0 +1,40 @@
+package org.spongycastle.jcajce.provider.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.util.Integers;
+
+public class SecretKeyUtil
+{
+ private static Map keySizes = new HashMap();
+
+ static
+ {
+ keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
+
+ keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
+ keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
+ keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256));
+
+ keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128));
+ keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
+ keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
+ }
+
+ public static int getKeySize(ASN1ObjectIdentifier oid)
+ {
+ Integer size = (Integer)keySizes.get(oid);
+
+ if (size != null)
+ {
+ return size.intValue();
+ }
+
+ return -1;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/GOST28147ParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/GOST28147ParameterSpec.java
new file mode 100644
index 000000000..2108d6f2c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/GOST28147ParameterSpec.java
@@ -0,0 +1,108 @@
+package org.spongycastle.jcajce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.crypto.engines.GOST28147Engine;
+import org.spongycastle.util.Arrays;
+
+/**
+ * A parameter spec for the GOST-28147 cipher.
+ */
+public class GOST28147ParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private byte[] iv = null;
+ private byte[] sBox = null;
+
+ public GOST28147ParameterSpec(
+ byte[] sBox)
+ {
+ this.sBox = new byte[sBox.length];
+
+ System.arraycopy(sBox, 0, this.sBox, 0, sBox.length);
+ }
+
+ public GOST28147ParameterSpec(
+ byte[] sBox,
+ byte[] iv)
+ {
+ this(sBox);
+ this.iv = new byte[iv.length];
+
+ System.arraycopy(iv, 0, this.iv, 0, iv.length);
+ }
+
+ public GOST28147ParameterSpec(
+ String sBoxName)
+ {
+ this.sBox = GOST28147Engine.getSBox(sBoxName);
+ }
+
+ public GOST28147ParameterSpec(
+ String sBoxName,
+ byte[] iv)
+ {
+ this(sBoxName);
+ this.iv = new byte[iv.length];
+
+ System.arraycopy(iv, 0, this.iv, 0, iv.length);
+ }
+
+ public GOST28147ParameterSpec(
+ ASN1ObjectIdentifier sBoxName,
+ byte[] iv)
+ {
+ this(getName(sBoxName));
+ this.iv = Arrays.clone(iv);
+ }
+
+ public byte[] getSbox()
+ {
+ return sBox;
+ }
+
+ /**
+ * Returns the IV or null if this parameter set does not contain an IV.
+ *
+ * @return the IV or null if this parameter set does not contain an IV.
+ */
+ public byte[] getIV()
+ {
+ if (iv == null)
+ {
+ return null;
+ }
+
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ private static Map oidMappings = new HashMap();
+
+ static
+ {
+ oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet, "E-A");
+ oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_B_ParamSet, "E-B");
+ oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_C_ParamSet, "E-C");
+ oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_D_ParamSet, "E-D");
+ }
+
+ private static String getName(ASN1ObjectIdentifier sBoxOid)
+ {
+ String sBoxName = (String)oidMappings.get(sBoxOid);
+
+ if (sBoxName == null)
+ {
+ throw new IllegalArgumentException("unknown OID: " + sBoxOid);
+ }
+
+ return sBoxName;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/PBKDF2KeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/PBKDF2KeySpec.java
new file mode 100644
index 000000000..68629058b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/PBKDF2KeySpec.java
@@ -0,0 +1,23 @@
+package org.spongycastle.jcajce.spec;
+
+import javax.crypto.spec.PBEKeySpec;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+public class PBKDF2KeySpec
+ extends PBEKeySpec
+{
+ private AlgorithmIdentifier prf;
+
+ public PBKDF2KeySpec(char[] password, byte[] salt, int iterationCount, int keySize, AlgorithmIdentifier prf)
+ {
+ super(password, salt, iterationCount, keySize);
+
+ this.prf = prf;
+ }
+
+ public AlgorithmIdentifier getPrf()
+ {
+ return prf;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/RepeatedSecretKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/RepeatedSecretKeySpec.java
new file mode 100644
index 000000000..b3a0e2f77
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/RepeatedSecretKeySpec.java
@@ -0,0 +1,34 @@
+package org.spongycastle.jcajce.spec;
+
+
+import javax.crypto.SecretKey;
+
+/**
+ * A simple object to indicate that a symmetric cipher should reuse the
+ * last key provided.
+ */
+public class RepeatedSecretKeySpec
+ implements SecretKey
+{
+ private String algorithm;
+
+ public RepeatedSecretKeySpec(String algorithm)
+ {
+ this.algorithm = algorithm;
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/SkeinParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/SkeinParameterSpec.java
new file mode 100644
index 000000000..ee3bb4346
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jcajce/spec/SkeinParameterSpec.java
@@ -0,0 +1,283 @@
+package org.spongycastle.jcajce.spec;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.security.spec.AlgorithmParameterSpec;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+
+/**
+ * Parameters for the Skein hash function - a series of byte[] strings identified by integer tags.
+ * <p/>
+ * Parameterised Skein can be used for:
+ * <ul>
+ * <li>MAC generation, by providing a {@link org.spongycastle.jcajce.spec.SkeinParameterSpec.Builder#setKey(byte[]) key}.</li>
+ * <li>Randomised hashing, by providing a {@link org.spongycastle.jcajce.spec.SkeinParameterSpec.Builder#setNonce(byte[]) nonce}.</li>
+ * <li>A hash function for digital signatures, associating a
+ * {@link org.spongycastle.jcajce.spec.SkeinParameterSpec.Builder#setPublicKey(byte[]) public key} with the message digest.</li>
+ * <li>A key derivation function, by providing a
+ * {@link org.spongycastle.jcajce.spec.SkeinParameterSpec.Builder#setKeyIdentifier(byte[]) key identifier}.</li>
+ * <li>Personalised hashing, by providing a
+ * {@link org.spongycastle.jcajce.spec.SkeinParameterSpec.Builder#setPersonalisation(java.util.Date, String, String) recommended format} or
+ * {@link org.spongycastle.jcajce.spec.SkeinParameterSpec.Builder#setPersonalisation(byte[]) arbitrary} personalisation string.</li>
+ * </ul>
+ *
+ * @see org.spongycastle.crypto.digests.SkeinEngine
+ * @see org.spongycastle.crypto.digests.SkeinDigest
+ * @see org.spongycastle.crypto.macs.SkeinMac
+ */
+public class SkeinParameterSpec
+ implements AlgorithmParameterSpec
+{
+ /**
+ * The parameter type for a secret key, supporting MAC or KDF functions: {@value
+ * #PARAM_TYPE_KEY}.
+ */
+ public static final int PARAM_TYPE_KEY = 0;
+
+ /**
+ * The parameter type for the Skein configuration block: {@value #PARAM_TYPE_CONFIG}.
+ */
+ public static final int PARAM_TYPE_CONFIG = 4;
+
+ /**
+ * The parameter type for a personalisation string: {@value #PARAM_TYPE_PERSONALISATION}.
+ */
+ public static final int PARAM_TYPE_PERSONALISATION = 8;
+
+ /**
+ * The parameter type for a public key: {@value #PARAM_TYPE_PUBLIC_KEY}.
+ */
+ public static final int PARAM_TYPE_PUBLIC_KEY = 12;
+
+ /**
+ * The parameter type for a key identifier string: {@value #PARAM_TYPE_KEY_IDENTIFIER}.
+ */
+ public static final int PARAM_TYPE_KEY_IDENTIFIER = 16;
+
+ /**
+ * The parameter type for a nonce: {@value #PARAM_TYPE_NONCE}.
+ */
+ public static final int PARAM_TYPE_NONCE = 20;
+
+ /**
+ * The parameter type for the message: {@value #PARAM_TYPE_MESSAGE}.
+ */
+ public static final int PARAM_TYPE_MESSAGE = 48;
+
+ /**
+ * The parameter type for the output transformation: {@value #PARAM_TYPE_OUTPUT}.
+ */
+ public static final int PARAM_TYPE_OUTPUT = 63;
+
+ private Map parameters;
+
+ public SkeinParameterSpec()
+ {
+ this(new HashMap());
+ }
+
+ private SkeinParameterSpec(Map parameters)
+ {
+ this.parameters = Collections.unmodifiableMap(parameters);
+ }
+
+ /**
+ * Obtains a map of type (Integer) to value (byte[]) for the parameters tracked in this object.
+ */
+ public Map getParameters()
+ {
+ return parameters;
+ }
+
+ /**
+ * Obtains the value of the {@link #PARAM_TYPE_KEY key parameter}, or <code>null</code> if not
+ * set.
+ */
+ public byte[] getKey()
+ {
+ return Arrays.clone((byte[])parameters.get(Integers.valueOf(PARAM_TYPE_KEY)));
+ }
+
+ /**
+ * Obtains the value of the {@link #PARAM_TYPE_PERSONALISATION personalisation parameter}, or
+ * <code>null</code> if not set.
+ */
+ public byte[] getPersonalisation()
+ {
+ return Arrays.clone((byte[])parameters.get(Integers.valueOf(PARAM_TYPE_PERSONALISATION)));
+ }
+
+ /**
+ * Obtains the value of the {@link #PARAM_TYPE_PUBLIC_KEY public key parameter}, or
+ * <code>null</code> if not set.
+ */
+ public byte[] getPublicKey()
+ {
+ return Arrays.clone((byte[])parameters.get(Integers.valueOf(PARAM_TYPE_PUBLIC_KEY)));
+ }
+
+ /**
+ * Obtains the value of the {@link #PARAM_TYPE_KEY_IDENTIFIER key identifier parameter}, or
+ * <code>null</code> if not set.
+ */
+ public byte[] getKeyIdentifier()
+ {
+ return Arrays.clone((byte[])parameters.get(Integers.valueOf(PARAM_TYPE_KEY_IDENTIFIER)));
+ }
+
+ /**
+ * Obtains the value of the {@link #PARAM_TYPE_NONCE nonce parameter}, or <code>null</code> if
+ * not set.
+ */
+ public byte[] getNonce()
+ {
+ return Arrays.clone((byte[])parameters.get(Integers.valueOf(PARAM_TYPE_NONCE)));
+ }
+
+ /**
+ * A builder for {@link org.spongycastle.jcajce.spec.SkeinParameterSpec}.
+ */
+ public static class Builder
+ {
+ private Map parameters = new HashMap();
+
+ public Builder()
+ {
+ }
+
+ public Builder(SkeinParameterSpec params)
+ {
+ Iterator keys = params.parameters.keySet().iterator();
+ while (keys.hasNext())
+ {
+ Integer key = (Integer)keys.next();
+ parameters.put(key, params.parameters.get(key));
+ }
+ }
+
+ /**
+ * Sets a parameters to apply to the Skein hash function.<br>
+ * Parameter types must be in the range 0,5..62, and cannot use the value {@value
+ * org.spongycastle.jcajce.spec.SkeinParameterSpec#PARAM_TYPE_MESSAGE} (reserved for message body).
+ * <p/>
+ * Parameters with type < {@value org.spongycastle.jcajce.spec.SkeinParameterSpec#PARAM_TYPE_MESSAGE} are processed before
+ * the message content, parameters with type > {@value org.spongycastle.jcajce.spec.SkeinParameterSpec#PARAM_TYPE_MESSAGE}
+ * are processed after the message and prior to output.
+ *
+ * @param type the type of the parameter, in the range 5..62.
+ * @param value the byte sequence of the parameter.
+ * @return
+ */
+ public Builder set(int type, byte[] value)
+ {
+ if (value == null)
+ {
+ throw new IllegalArgumentException("Parameter value must not be null.");
+ }
+ if ((type != PARAM_TYPE_KEY)
+ && (type <= PARAM_TYPE_CONFIG || type >= PARAM_TYPE_OUTPUT || type == PARAM_TYPE_MESSAGE))
+ {
+ throw new IllegalArgumentException("Parameter types must be in the range 0,5..47,49..62.");
+ }
+ if (type == PARAM_TYPE_CONFIG)
+ {
+ throw new IllegalArgumentException("Parameter type " + PARAM_TYPE_CONFIG
+ + " is reserved for internal use.");
+ }
+ this.parameters.put(Integers.valueOf(type), value);
+ return this;
+ }
+
+ /**
+ * Sets the {@link org.spongycastle.jcajce.spec.SkeinParameterSpec#PARAM_TYPE_KEY} parameter.
+ */
+ public Builder setKey(byte[] key)
+ {
+ return set(PARAM_TYPE_KEY, key);
+ }
+
+ /**
+ * Sets the {@link org.spongycastle.jcajce.spec.SkeinParameterSpec#PARAM_TYPE_PERSONALISATION} parameter.
+ */
+ public Builder setPersonalisation(byte[] personalisation)
+ {
+ return set(PARAM_TYPE_PERSONALISATION, personalisation);
+ }
+
+ /**
+ * Implements the recommended personalisation format for Skein defined in Section 4.11 of
+ * the Skein 1.3 specification.
+ * <p/>
+ * The format is <code>YYYYMMDD email@address distinguisher</code>, encoded to a byte
+ * sequence using UTF-8 encoding.
+ *
+ * @param date the date the personalised application of the Skein was defined.
+ * @param emailAddress the email address of the creation of the personalised application.
+ * @param distinguisher an arbitrary personalisation string distinguishing the application.
+ * @return
+ */
+ public Builder setPersonalisation(Date date, String emailAddress, String distinguisher)
+ {
+ try
+ {
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ final OutputStreamWriter out = new OutputStreamWriter(bout, "UTF-8");
+ final DateFormat format = new SimpleDateFormat("YYYYMMDD");
+ out.write(format.format(date));
+ out.write(" ");
+ out.write(emailAddress);
+ out.write(" ");
+ out.write(distinguisher);
+ out.close();
+ return set(PARAM_TYPE_PERSONALISATION, bout.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("Byte I/O failed: " + e);
+ }
+ }
+
+ /**
+ * Sets the {@link org.spongycastle.jcajce.spec.SkeinParameterSpec#PARAM_TYPE_KEY_IDENTIFIER} parameter.
+ */
+ public Builder setPublicKey(byte[] publicKey)
+ {
+ return set(PARAM_TYPE_PUBLIC_KEY, publicKey);
+ }
+
+ /**
+ * Sets the {@link org.spongycastle.jcajce.spec.SkeinParameterSpec#PARAM_TYPE_KEY_IDENTIFIER} parameter.
+ */
+ public Builder setKeyIdentifier(byte[] keyIdentifier)
+ {
+ return set(PARAM_TYPE_KEY_IDENTIFIER, keyIdentifier);
+ }
+
+ /**
+ * Sets the {@link org.spongycastle.jcajce.spec.SkeinParameterSpec#PARAM_TYPE_NONCE} parameter.
+ */
+ public Builder setNonce(byte[] nonce)
+ {
+ return set(PARAM_TYPE_NONCE, nonce);
+ }
+
+ /**
+ * Constructs a new {@link org.spongycastle.jcajce.spec.SkeinParameterSpec} instance with the parameters provided to this
+ * builder.
+ */
+ public SkeinParameterSpec build()
+ {
+ return new SkeinParameterSpec(parameters);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECGOST3410NamedCurveTable.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECGOST3410NamedCurveTable.java
new file mode 100644
index 000000000..49c525ad7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECGOST3410NamedCurveTable.java
@@ -0,0 +1,61 @@
+package org.spongycastle.jce;
+
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+
+/**
+ * a table of locally supported named curves.
+ */
+public class ECGOST3410NamedCurveTable
+{
+ /**
+ * return a parameter spec representing the passed in named
+ * curve. The routine returns null if the curve is not present.
+ *
+ * @param name the name of the curve requested
+ * @return a parameter spec for the curve, null if it is not available.
+ */
+ public static ECNamedCurveParameterSpec getParameterSpec(
+ String name)
+ {
+ ECDomainParameters ecP = ECGOST3410NamedCurves.getByName(name);
+ if (ecP == null)
+ {
+ try
+ {
+ ecP = ECGOST3410NamedCurves.getByOID(new ASN1ObjectIdentifier(name));
+ }
+ catch (IllegalArgumentException e)
+ {
+ return null; // not an oid.
+ }
+ }
+
+ if (ecP == null)
+ {
+ return null;
+ }
+
+ return new ECNamedCurveParameterSpec(
+ name,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+
+ /**
+ * return an enumeration of the names of the available curves.
+ *
+ * @return an enumeration of the names of the available curves.
+ */
+ public static Enumeration getNames()
+ {
+ return ECGOST3410NamedCurves.getNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECKeyUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECKeyUtil.java
new file mode 100644
index 000000000..8b4b38915
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECKeyUtil.java
@@ -0,0 +1,229 @@
+package org.spongycastle.jce;
+
+import java.io.UnsupportedEncodingException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * Utility class to allow conversion of EC key parameters to explicit from named
+ * curves and back (where possible).
+ */
+public class ECKeyUtil
+{
+ /**
+ * Convert a passed in public EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param providerName provider name to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ */
+ public static PublicKey publicToExplicitParameters(PublicKey key, String providerName)
+ throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ Provider provider = Security.getProvider(providerName);
+
+ if (provider == null)
+ {
+ throw new NoSuchProviderException("cannot find provider: " + providerName);
+ }
+
+ return publicToExplicitParameters(key, provider);
+ }
+
+ /**
+ * Convert a passed in public EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param provider provider to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ */
+ public static PublicKey publicToExplicitParameters(PublicKey key, Provider provider)
+ throws IllegalArgumentException, NoSuchAlgorithmException
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded()));
+
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ throw new IllegalArgumentException("cannot convert GOST key to explicit parameters.");
+ }
+ else
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ X9ECParameters curveParams;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+ curveParams = ECUtil.getNamedCurveByOid(oid);
+ // ignore seed value due to JDK bug
+ curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH());
+ }
+ else
+ {
+ return key; // already explicit
+ }
+
+ params = new X962Parameters(curveParams);
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.getPublicKeyData().getBytes());
+
+ KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider);
+
+ return keyFact.generatePublic(new X509EncodedKeySpec(info.getEncoded()));
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ { // shouldn't really happen...
+ throw new UnexpectedException(e);
+ }
+ }
+
+ /**
+ * Convert a passed in private EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param providerName provider name to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ */
+ public static PrivateKey privateToExplicitParameters(PrivateKey key, String providerName)
+ throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ Provider provider = Security.getProvider(providerName);
+
+ if (provider == null)
+ {
+ throw new NoSuchProviderException("cannot find provider: " + providerName);
+ }
+
+ return privateToExplicitParameters(key, provider);
+ }
+
+ /**
+ * Convert a passed in private EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param provider provider to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ */
+ public static PrivateKey privateToExplicitParameters(PrivateKey key, Provider provider)
+ throws IllegalArgumentException, NoSuchAlgorithmException
+ {
+ try
+ {
+ PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded()));
+
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ throw new UnsupportedEncodingException("cannot convert GOST key to explicit parameters.");
+ }
+ else
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ X9ECParameters curveParams;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+ curveParams = ECUtil.getNamedCurveByOid(oid);
+ // ignore seed value due to JDK bug
+ curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH());
+ }
+ else
+ {
+ return key; // already explicit
+ }
+
+ params = new X962Parameters(curveParams);
+
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.parsePrivateKey());
+
+ KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider);
+
+ return keyFact.generatePrivate(new PKCS8EncodedKeySpec(info.getEncoded()));
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ { // shouldn't really happen
+ throw new UnexpectedException(e);
+ }
+ }
+
+ private static class UnexpectedException
+ extends RuntimeException
+ {
+ private Throwable cause;
+
+ UnexpectedException(Throwable cause)
+ {
+ super(cause.toString());
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECNamedCurveTable.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECNamedCurveTable.java
new file mode 100644
index 000000000..1a1f1b8a5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECNamedCurveTable.java
@@ -0,0 +1,60 @@
+package org.spongycastle.jce;
+
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+
+/**
+ * a table of locally supported named curves.
+ */
+public class ECNamedCurveTable
+{
+ /**
+ * return a parameter spec representing the passed in named
+ * curve. The routine returns null if the curve is not present.
+ *
+ * @param name the name of the curve requested
+ * @return a parameter spec for the curve, null if it is not available.
+ */
+ public static ECNamedCurveParameterSpec getParameterSpec(
+ String name)
+ {
+ X9ECParameters ecP = org.spongycastle.asn1.x9.ECNamedCurveTable.getByName(name);
+ if (ecP == null)
+ {
+ try
+ {
+ ecP = org.spongycastle.asn1.x9.ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(name));
+ }
+ catch (IllegalArgumentException e)
+ {
+ // ignore - not an oid
+ }
+ }
+
+ if (ecP == null)
+ {
+ return null;
+ }
+
+ return new ECNamedCurveParameterSpec(
+ name,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+
+ /**
+ * return an enumeration of the names of the available curves.
+ *
+ * @return an enumeration of the names of the available curves.
+ */
+ public static Enumeration getNames()
+ {
+ return org.spongycastle.asn1.x9.ECNamedCurveTable.getNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECPointUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECPointUtil.java
new file mode 100644
index 000000000..fa9fa62fb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/ECPointUtil.java
@@ -0,0 +1,56 @@
+package org.spongycastle.jce;
+
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+import org.spongycastle.math.ec.ECCurve;
+
+/**
+ * Utility class for handling EC point decoding.
+ */
+public class ECPointUtil
+{
+ /**
+ * Decode a point on this curve which has been encoded using point
+ * compression (X9.62 s 4.2.1 and 4.2.2) or regular encoding.
+ *
+ * @param curve
+ * The elliptic curve.
+ * @param encoded
+ * The encoded point.
+ * @return the decoded point.
+ */
+ public static ECPoint decodePoint(
+ EllipticCurve curve,
+ byte[] encoded)
+ {
+ ECCurve c = null;
+
+ if (curve.getField() instanceof ECFieldFp)
+ {
+ c = new ECCurve.Fp(
+ ((ECFieldFp)curve.getField()).getP(), curve.getA(), curve.getB());
+ }
+ else
+ {
+ int k[] = ((ECFieldF2m)curve.getField()).getMidTermsOfReductionPolynomial();
+
+ if (k.length == 3)
+ {
+ c = new ECCurve.F2m(
+ ((ECFieldF2m)curve.getField()).getM(), k[2], k[1], k[0], curve.getA(), curve.getB());
+ }
+ else
+ {
+ c = new ECCurve.F2m(
+ ((ECFieldF2m)curve.getField()).getM(), k[0], curve.getA(), curve.getB());
+ }
+ }
+
+ org.spongycastle.math.ec.ECPoint p = c.decodePoint(encoded);
+
+ return new ECPoint(p.getAffineXCoord().toBigInteger(), p.getAffineYCoord().toBigInteger());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/MultiCertStoreParameters.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/MultiCertStoreParameters.java
new file mode 100644
index 000000000..8762494b2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/MultiCertStoreParameters.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jce;
+
+import java.security.cert.CertStoreParameters;
+import java.util.Collection;
+
+public class MultiCertStoreParameters
+ implements CertStoreParameters
+{
+ private Collection certStores;
+ private boolean searchAllStores;
+
+ /**
+ * Create a parameters object which specifies searching of all the passed in stores.
+ *
+ * @param certStores CertStores making up the multi CertStore
+ */
+ public MultiCertStoreParameters(Collection certStores)
+ {
+ this(certStores, true);
+ }
+
+ /**
+ * Create a parameters object which can be to used to make a multi store made up
+ * of the passed in CertStores. If the searchAllStores parameter is false, any search on
+ * the multi-store will terminate as soon as a search query produces a result.
+ *
+ * @param certStores CertStores making up the multi CertStore
+ * @param searchAllStores true if all CertStores should be searched on request, false if a result
+ * should be returned on the first successful CertStore query.
+ */
+ public MultiCertStoreParameters(Collection certStores, boolean searchAllStores)
+ {
+ this.certStores = certStores;
+ this.searchAllStores = searchAllStores;
+ }
+
+ public Collection getCertStores()
+ {
+ return certStores;
+ }
+
+ public boolean getSearchAllStores()
+ {
+ return searchAllStores;
+ }
+
+ public Object clone()
+ {
+ return this;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PKCS10CertificationRequest.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PKCS10CertificationRequest.java
new file mode 100644
index 000000000..74c1ba169
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PKCS10CertificationRequest.java
@@ -0,0 +1,640 @@
+package org.spongycastle.jce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.CertificationRequest;
+import org.spongycastle.asn1.pkcs.CertificationRequestInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+/**
+ * A class for verifying and creating PKCS10 Certification requests.
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ * signature BIT STRING
+ * }
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version INTEGER { v1(0) } (v1,...),
+ * subject Name,
+ * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ * attributes [0] Attributes{{ CRIAttributes }}
+ * }
+ *
+ * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
+ *
+ * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ * type ATTRIBUTE.&id({IOSet}),
+ * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ * }
+ * </pre>
+ * @deprecated use classes in org.spongycastle.pkcs.
+ */
+public class PKCS10CertificationRequest
+ extends CertificationRequest
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Hashtable keyAlgorithms = new Hashtable();
+ private static Hashtable oids = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("RSAWITHSHA1", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // reverse mappings
+ //
+ oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+
+ oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+ oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+
+ //
+ // key types
+ //
+ keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+
+ //
+ // RFC 4491
+ //
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+ params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ private static ASN1Sequence toDERSequence(
+ byte[] bytes)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+
+ return (ASN1Sequence)dIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("badly encoded request");
+ }
+ }
+
+ /**
+ * construct a PKCS10 certification request from a DER encoded
+ * byte stream.
+ */
+ public PKCS10CertificationRequest(
+ byte[] bytes)
+ {
+ super(toDERSequence(bytes));
+ }
+
+ public PKCS10CertificationRequest(
+ ASN1Sequence sequence)
+ {
+ super(sequence);
+ }
+
+ /**
+ * create a PKCS10 certfication request using the BC provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X509Name subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ this(signatureAlgorithm, subject, key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ private static X509Name convertName(
+ X500Principal name)
+ {
+ try
+ {
+ return new X509Principal(name.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't convert name");
+ }
+ }
+
+ /**
+ * create a PKCS10 certfication request using the BC provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X500Principal subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ /**
+ * create a PKCS10 certfication request using the named provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X500Principal subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, provider);
+ }
+
+ /**
+ * create a PKCS10 certfication request using the named provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X509Name subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ String algorithmName = Strings.toUpperCase(signatureAlgorithm);
+ DERObjectIdentifier sigOID = (DERObjectIdentifier)algorithms.get(algorithmName);
+
+ if (sigOID == null)
+ {
+ try
+ {
+ sigOID = new DERObjectIdentifier(algorithmName);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+ }
+
+ if (subject == null)
+ {
+ throw new IllegalArgumentException("subject must not be null");
+ }
+
+ if (key == null)
+ {
+ throw new IllegalArgumentException("public key must not be null");
+ }
+
+ if (noParams.contains(sigOID))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID);
+ }
+ else if (params.containsKey(algorithmName))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);
+ }
+
+ try
+ {
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(key.getEncoded());
+ this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo(seq), attributes);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't encode public key");
+ }
+
+ Signature sig;
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm);
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+
+ sig.initSign(signingKey);
+
+ try
+ {
+ sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("exception encoding TBS cert request - " + e);
+ }
+
+ this.sigBits = new DERBitString(sig.sign());
+ }
+
+ /**
+ * return the public key associated with the certification request -
+ * the public key is created using the BC provider.
+ */
+ public PublicKey getPublicKey()
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
+ {
+ return getPublicKey(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public PublicKey getPublicKey(
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException
+ {
+ SubjectPublicKeyInfo subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
+
+
+ try
+ {
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
+ AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithm();
+ try
+ {
+ if (provider == null)
+ {
+ return KeyFactory.getInstance(keyAlg.getAlgorithm().getId()).generatePublic(xspec);
+ }
+ else
+ {
+ return KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), provider).generatePublic(xspec);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (keyAlgorithms.get(keyAlg.getObjectId()) != null)
+ {
+ String keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getObjectId());
+
+ if (provider == null)
+ {
+ return KeyFactory.getInstance(keyAlgorithm).generatePublic(xspec);
+ }
+ else
+ {
+ return KeyFactory.getInstance(keyAlgorithm, provider).generatePublic(xspec);
+ }
+ }
+
+ throw e;
+ }
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new InvalidKeyException("error decoding public key");
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeyException("error decoding public key");
+ }
+ }
+
+ /**
+ * verify the request using the BC provider.
+ */
+ public boolean verify()
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ return verify(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ /**
+ * verify the request using the passed in provider.
+ */
+ public boolean verify(
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ return verify(this.getPublicKey(provider), provider);
+ }
+
+ /**
+ * verify the request using the passed in public key and the provider..
+ */
+ public boolean verify(
+ PublicKey pubKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ try
+ {
+ if (provider == null)
+ {
+ sig = Signature.getInstance(getSignatureName(sigAlgId));
+ }
+ else
+ {
+ sig = Signature.getInstance(getSignatureName(sigAlgId), provider);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(sigAlgId.getObjectId()) != null)
+ {
+ String signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId());
+
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm);
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ setSignatureParameters(sig, sigAlgId.getParameters());
+
+ sig.initVerify(pubKey);
+
+ try
+ {
+ sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("exception encoding TBS cert request - " + e);
+ }
+
+ return sig.verify(sigBits.getBytes());
+ }
+
+ /**
+ * return a DER encoded byte array representing this object
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ return this.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ private void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+
+ if (signature.getAlgorithm().endsWith("MGF1"))
+ {
+ try
+ {
+ signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ private static String getDigestAlgName(
+ DERObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PKCS12Util.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PKCS12Util.java
new file mode 100644
index 000000000..ac0175654
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PKCS12Util.java
@@ -0,0 +1,126 @@
+package org.spongycastle.jce;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+
+/**
+ * Utility class for reencoding PKCS#12 files to definite length.
+ */
+public class PKCS12Util
+{
+ /**
+ * Just re-encode the outer layer of the PKCS#12 file to definite length encoding.
+ *
+ * @param berPKCS12File - original PKCS#12 file
+ * @return a byte array representing the DER encoding of the PFX structure
+ * @throws IOException
+ */
+ public static byte[] convertToDefiniteLength(byte[] berPKCS12File)
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ Pfx pfx = Pfx.getInstance(berPKCS12File);
+
+ bOut.reset();
+
+ dOut.writeObject(pfx);
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Re-encode the PKCS#12 structure to definite length encoding at the inner layer
+ * as well, recomputing the MAC accordingly.
+ *
+ * @param berPKCS12File - original PKCS12 file.
+ * @param provider - provider to use for MAC calculation.
+ * @return a byte array representing the DER encoding of the PFX structure.
+ * @throws IOException on parsing, encoding errors.
+ */
+ public static byte[] convertToDefiniteLength(byte[] berPKCS12File, char[] passwd, String provider)
+ throws IOException
+ {
+ Pfx pfx = Pfx.getInstance(berPKCS12File);
+
+ ContentInfo info = pfx.getAuthSafe();
+
+ ASN1OctetString content = ASN1OctetString.getInstance(info.getContent());
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ ASN1InputStream contentIn = new ASN1InputStream(content.getOctets());
+ ASN1Primitive obj = contentIn.readObject();
+
+ dOut.writeObject(obj);
+
+ info = new ContentInfo(info.getContentType(), new DEROctetString(bOut.toByteArray()));
+
+ MacData mData = pfx.getMacData();
+ try
+ {
+ int itCount = mData.getIterationCount().intValue();
+ byte[] data = ASN1OctetString.getInstance(info.getContent()).getOctets();
+ byte[] res = calculatePbeMac(mData.getMac().getAlgorithmId().getObjectId(), mData.getSalt(), itCount, passwd, data, provider);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(mData.getMac().getAlgorithmId().getObjectId(), DERNull.INSTANCE);
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mData.getSalt(), itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+
+ pfx = new Pfx(info, mData);
+
+ bOut.reset();
+
+ dOut.writeObject(pfx);
+
+ return bOut.toByteArray();
+ }
+
+ private static byte[] calculatePbeMac(
+ DERObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ byte[] data,
+ String provider)
+ throws Exception
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), provider);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ SecretKey key = keyFact.generateSecret(pbeSpec);
+
+ Mac mac = Mac.getInstance(oid.getId(), provider);
+ mac.init(key, defParams);
+ mac.update(data);
+
+ return mac.doFinal();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PrincipalUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PrincipalUtil.java
new file mode 100644
index 000000000..3d6d6f4da
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/PrincipalUtil.java
@@ -0,0 +1,81 @@
+package org.spongycastle.jce;
+
+import java.io.IOException;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.TBSCertificateStructure;
+import org.spongycastle.asn1.x509.X509Name;
+
+/**
+ * a utility class that will extract X509Principal objects from X.509 certificates.
+ * <p>
+ * Use this in preference to trying to recreate a principal from a String, not all
+ * DNs are what they should be, so it's best to leave them encoded where they
+ * can be.
+ */
+public class PrincipalUtil
+{
+ /**
+ * return the issuer of the given cert as an X509PrincipalObject.
+ */
+ public static X509Principal getIssuerX509Principal(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(
+ ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
+
+ return new X509Principal(X509Name.getInstance(tbsCert.getIssuer()));
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ /**
+ * return the subject of the given cert as an X509PrincipalObject.
+ */
+ public static X509Principal getSubjectX509Principal(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(
+ ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
+ return new X509Principal(X509Name.getInstance(tbsCert.getSubject()));
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ /**
+ * return the issuer of the given CRL as an X509PrincipalObject.
+ */
+ public static X509Principal getIssuerX509Principal(
+ X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ TBSCertList tbsCertList = TBSCertList.getInstance(
+ ASN1Primitive.fromByteArray(crl.getTBSCertList()));
+
+ return new X509Principal(X509Name.getInstance(tbsCertList.getIssuer()));
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509KeyUsage.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509KeyUsage.java
new file mode 100644
index 000000000..227670d6b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509KeyUsage.java
@@ -0,0 +1,57 @@
+package org.spongycastle.jce;
+
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.x509.KeyUsage;
+
+/**
+ * A holding class for constructing an X509 Key Usage extension.
+ *
+ * <pre>
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
+ *
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ * </pre>
+ */
+public class X509KeyUsage
+ extends ASN1Object
+{
+ public static final int digitalSignature = 1 << 7;
+ public static final int nonRepudiation = 1 << 6;
+ public static final int keyEncipherment = 1 << 5;
+ public static final int dataEncipherment = 1 << 4;
+ public static final int keyAgreement = 1 << 3;
+ public static final int keyCertSign = 1 << 2;
+ public static final int cRLSign = 1 << 1;
+ public static final int encipherOnly = 1 << 0;
+ public static final int decipherOnly = 1 << 15;
+
+ private int usage = 0;
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment)
+ */
+ public X509KeyUsage(
+ int usage)
+ {
+ this.usage = usage;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return new KeyUsage(usage).toASN1Primitive();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509LDAPCertStoreParameters.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509LDAPCertStoreParameters.java
new file mode 100644
index 000000000..88259ec08
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509LDAPCertStoreParameters.java
@@ -0,0 +1,1258 @@
+package org.spongycastle.jce;
+
+import org.spongycastle.x509.X509StoreParameters;
+
+import java.security.cert.CertStoreParameters;
+import java.security.cert.LDAPCertStoreParameters;
+
+/**
+ * An expanded set of parameters for an LDAPCertStore
+ */
+public class X509LDAPCertStoreParameters
+ implements X509StoreParameters, CertStoreParameters
+{
+
+ private String ldapURL;
+
+ private String baseDN;
+
+ // LDAP attributes, where data is stored
+
+ private String userCertificateAttribute;
+
+ private String cACertificateAttribute;
+
+ private String crossCertificateAttribute;
+
+ private String certificateRevocationListAttribute;
+
+ private String deltaRevocationListAttribute;
+
+ private String authorityRevocationListAttribute;
+
+ private String attributeCertificateAttributeAttribute;
+
+ private String aACertificateAttribute;
+
+ private String attributeDescriptorCertificateAttribute;
+
+ private String attributeCertificateRevocationListAttribute;
+
+ private String attributeAuthorityRevocationListAttribute;
+
+ // LDAP attributes with which data can be found
+
+ private String ldapUserCertificateAttributeName;
+
+ private String ldapCACertificateAttributeName;
+
+ private String ldapCrossCertificateAttributeName;
+
+ private String ldapCertificateRevocationListAttributeName;
+
+ private String ldapDeltaRevocationListAttributeName;
+
+ private String ldapAuthorityRevocationListAttributeName;
+
+ private String ldapAttributeCertificateAttributeAttributeName;
+
+ private String ldapAACertificateAttributeName;
+
+ private String ldapAttributeDescriptorCertificateAttributeName;
+
+ private String ldapAttributeCertificateRevocationListAttributeName;
+
+ private String ldapAttributeAuthorityRevocationListAttributeName;
+
+ // certificates and CRLs subject or issuer DN attributes, which must be
+ // matched against ldap attribute names
+
+ private String userCertificateSubjectAttributeName;
+
+ private String cACertificateSubjectAttributeName;
+
+ private String crossCertificateSubjectAttributeName;
+
+ private String certificateRevocationListIssuerAttributeName;
+
+ private String deltaRevocationListIssuerAttributeName;
+
+ private String authorityRevocationListIssuerAttributeName;
+
+ private String attributeCertificateAttributeSubjectAttributeName;
+
+ private String aACertificateSubjectAttributeName;
+
+ private String attributeDescriptorCertificateSubjectAttributeName;
+
+ private String attributeCertificateRevocationListIssuerAttributeName;
+
+ private String attributeAuthorityRevocationListIssuerAttributeName;
+
+ private String searchForSerialNumberIn;
+
+ public static class Builder
+ {
+ private String ldapURL;
+
+ private String baseDN;
+
+ // LDAP attributes, where data is stored
+
+ private String userCertificateAttribute;
+
+ private String cACertificateAttribute;
+
+ private String crossCertificateAttribute;
+
+ private String certificateRevocationListAttribute;
+
+ private String deltaRevocationListAttribute;
+
+ private String authorityRevocationListAttribute;
+
+ private String attributeCertificateAttributeAttribute;
+
+ private String aACertificateAttribute;
+
+ private String attributeDescriptorCertificateAttribute;
+
+ private String attributeCertificateRevocationListAttribute;
+
+ private String attributeAuthorityRevocationListAttribute;
+
+ // LDAP attributes with which data can be found
+
+ private String ldapUserCertificateAttributeName;
+
+ private String ldapCACertificateAttributeName;
+
+ private String ldapCrossCertificateAttributeName;
+
+ private String ldapCertificateRevocationListAttributeName;
+
+ private String ldapDeltaRevocationListAttributeName;
+
+ private String ldapAuthorityRevocationListAttributeName;
+
+ private String ldapAttributeCertificateAttributeAttributeName;
+
+ private String ldapAACertificateAttributeName;
+
+ private String ldapAttributeDescriptorCertificateAttributeName;
+
+ private String ldapAttributeCertificateRevocationListAttributeName;
+
+ private String ldapAttributeAuthorityRevocationListAttributeName;
+
+ // certificates and CRLs subject or issuer DN attributes, which must be
+ // matched against ldap attribute names
+
+ private String userCertificateSubjectAttributeName;
+
+ private String cACertificateSubjectAttributeName;
+
+ private String crossCertificateSubjectAttributeName;
+
+ private String certificateRevocationListIssuerAttributeName;
+
+ private String deltaRevocationListIssuerAttributeName;
+
+ private String authorityRevocationListIssuerAttributeName;
+
+ private String attributeCertificateAttributeSubjectAttributeName;
+
+ private String aACertificateSubjectAttributeName;
+
+ private String attributeDescriptorCertificateSubjectAttributeName;
+
+ private String attributeCertificateRevocationListIssuerAttributeName;
+
+ private String attributeAuthorityRevocationListIssuerAttributeName;
+
+ private String searchForSerialNumberIn;
+
+ public Builder()
+ {
+ this("ldap://localhost:389", "");
+ }
+
+ public Builder(String ldapURL, String baseDN)
+ {
+ this.ldapURL = ldapURL;
+ if (baseDN == null)
+ {
+ this.baseDN = "";
+ }
+ else
+ {
+ this.baseDN = baseDN;
+ }
+
+ this.userCertificateAttribute = "userCertificate";
+ this.cACertificateAttribute = "cACertificate";
+ this.crossCertificateAttribute = "crossCertificatePair";
+ this.certificateRevocationListAttribute = "certificateRevocationList";
+ this.deltaRevocationListAttribute = "deltaRevocationList";
+ this.authorityRevocationListAttribute = "authorityRevocationList";
+ this.attributeCertificateAttributeAttribute = "attributeCertificateAttribute";
+ this.aACertificateAttribute = "aACertificate";
+ this.attributeDescriptorCertificateAttribute = "attributeDescriptorCertificate";
+ this.attributeCertificateRevocationListAttribute = "attributeCertificateRevocationList";
+ this.attributeAuthorityRevocationListAttribute = "attributeAuthorityRevocationList";
+ this.ldapUserCertificateAttributeName = "cn";
+ this.ldapCACertificateAttributeName = "cn ou o";
+ this.ldapCrossCertificateAttributeName = "cn ou o";
+ this.ldapCertificateRevocationListAttributeName = "cn ou o";
+ this.ldapDeltaRevocationListAttributeName = "cn ou o";
+ this.ldapAuthorityRevocationListAttributeName = "cn ou o";
+ this.ldapAttributeCertificateAttributeAttributeName = "cn";
+ this.ldapAACertificateAttributeName = "cn o ou";
+ this.ldapAttributeDescriptorCertificateAttributeName = "cn o ou";
+ this.ldapAttributeCertificateRevocationListAttributeName = "cn o ou";
+ this.ldapAttributeAuthorityRevocationListAttributeName = "cn o ou";
+ this.userCertificateSubjectAttributeName = "cn";
+ this.cACertificateSubjectAttributeName = "o ou";
+ this.crossCertificateSubjectAttributeName = "o ou";
+ this.certificateRevocationListIssuerAttributeName = "o ou";
+ this.deltaRevocationListIssuerAttributeName = "o ou";
+ this.authorityRevocationListIssuerAttributeName = "o ou";
+ this.attributeCertificateAttributeSubjectAttributeName = "cn";
+ this.aACertificateSubjectAttributeName = "o ou";
+ this.attributeDescriptorCertificateSubjectAttributeName = "o ou";
+ this.attributeCertificateRevocationListIssuerAttributeName = "o ou";
+ this.attributeAuthorityRevocationListIssuerAttributeName = "o ou";
+ this.searchForSerialNumberIn = "uid serialNumber cn";
+ }
+
+ /**
+ * @param userCertificateAttribute Attribute name(s) in the LDAP directory where end certificates
+ * are stored. Separated by space. Defaults to "userCertificate"
+ * if <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setUserCertificateAttribute(String userCertificateAttribute)
+ {
+ this.userCertificateAttribute = userCertificateAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param cACertificateAttribute Attribute name(s) in the LDAP directory where CA certificates
+ * are stored. Separated by space. Defaults to "cACertificate" if
+ * <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setCACertificateAttribute(String cACertificateAttribute)
+ {
+ this.cACertificateAttribute = cACertificateAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param crossCertificateAttribute Attribute name(s), where the cross certificates are stored.
+ * Separated by space. Defaults to "crossCertificatePair" if
+ * <code>null</code>
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setCrossCertificateAttribute(String crossCertificateAttribute)
+ {
+ this.crossCertificateAttribute = crossCertificateAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param certificateRevocationListAttribute
+ * Attribute name(s) in the LDAP directory where CRLs are stored.
+ * Separated by space. Defaults to "certificateRevocationList" if
+ * <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setCertificateRevocationListAttribute(String certificateRevocationListAttribute)
+ {
+ this.certificateRevocationListAttribute = certificateRevocationListAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param deltaRevocationListAttribute Attribute name(s) in the LDAP directory where delta RLs are
+ * stored. Separated by space. Defaults to "deltaRevocationList"
+ * if <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setDeltaRevocationListAttribute(String deltaRevocationListAttribute)
+ {
+ this.deltaRevocationListAttribute = deltaRevocationListAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param authorityRevocationListAttribute
+ * Attribute name(s) in the LDAP directory where CRLs for
+ * authorities are stored. Separated by space. Defaults to
+ * "authorityRevocationList" if <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAuthorityRevocationListAttribute(String authorityRevocationListAttribute)
+ {
+ this.authorityRevocationListAttribute = authorityRevocationListAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param attributeCertificateAttributeAttribute
+ * Attribute name(s) in the LDAP directory where end attribute
+ * certificates are stored. Separated by space. Defaults to
+ * "attributeCertificateAttribute" if <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAttributeCertificateAttributeAttribute(String attributeCertificateAttributeAttribute)
+ {
+ this.attributeCertificateAttributeAttribute = attributeCertificateAttributeAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param aACertificateAttribute Attribute name(s) in the LDAP directory where attribute
+ * certificates for attribute authorities are stored. Separated
+ * by space. Defaults to "aACertificate" if <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAACertificateAttribute(String aACertificateAttribute)
+ {
+ this.aACertificateAttribute = aACertificateAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param attributeDescriptorCertificateAttribute
+ * Attribute name(s) in the LDAP directory where self signed
+ * attribute certificates for attribute authorities are stored.
+ * Separated by space. Defaults to
+ * "attributeDescriptorCertificate" if <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAttributeDescriptorCertificateAttribute(String attributeDescriptorCertificateAttribute)
+ {
+ this.attributeDescriptorCertificateAttribute = attributeDescriptorCertificateAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param attributeCertificateRevocationListAttribute
+ * Attribute name(s) in the LDAP directory where CRLs for
+ * attribute certificates are stored. Separated by space.
+ * Defaults to "attributeCertificateRevocationList" if
+ * <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAttributeCertificateRevocationListAttribute(String attributeCertificateRevocationListAttribute)
+ {
+ this.attributeCertificateRevocationListAttribute = attributeCertificateRevocationListAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param attributeAuthorityRevocationListAttribute
+ * Attribute name(s) in the LDAP directory where RLs for
+ * attribute authority attribute certificates are stored.
+ * Separated by space. Defaults to
+ * "attributeAuthorityRevocationList" if <code>null</code>.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAttributeAuthorityRevocationListAttribute(String attributeAuthorityRevocationListAttribute)
+ {
+ this.attributeAuthorityRevocationListAttribute = attributeAuthorityRevocationListAttribute;
+
+ return this;
+ }
+
+ /**
+ * @param ldapUserCertificateAttributeName
+ * The attribute name(s) in the LDAP directory where to search
+ * for the attribute value of the specified
+ * <code>userCertificateSubjectAttributeName</code>. E.g. if
+ * "cn" is used to put information about the subject for end
+ * certificates, then specify "cn".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapUserCertificateAttributeName(String ldapUserCertificateAttributeName)
+ {
+ this.ldapUserCertificateAttributeName = ldapUserCertificateAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapCACertificateAttributeName The attribute name(s) in the LDAP directory where to search
+ * for the attribute value of the specified
+ * <code>cACertificateSubjectAttributeName</code>. E.g. if
+ * "ou" is used to put information about the subject for CA
+ * certificates, then specify "ou".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapCACertificateAttributeName(String ldapCACertificateAttributeName)
+ {
+ this.ldapCACertificateAttributeName = ldapCACertificateAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapCrossCertificateAttributeName
+ * The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>crossCertificateSubjectAttributeName</code>. E.g. if
+ * "o" is used to put information about the subject for cross
+ * certificates, then specify "o".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapCrossCertificateAttributeName(String ldapCrossCertificateAttributeName)
+ {
+ this.ldapCrossCertificateAttributeName = ldapCrossCertificateAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapCertificateRevocationListAttributeName
+ * The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>certificateRevocationListIssuerAttributeName</code>.
+ * E.g. if "ou" is used to put information about the issuer of
+ * CRLs, specify "ou".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapCertificateRevocationListAttributeName(String ldapCertificateRevocationListAttributeName)
+ {
+ this.ldapCertificateRevocationListAttributeName = ldapCertificateRevocationListAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapDeltaRevocationListAttributeName
+ * The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>deltaRevocationListIssuerAttributeName</code>. E.g.
+ * if "ou" is used to put information about the issuer of CRLs,
+ * specify "ou".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapDeltaRevocationListAttributeName(String ldapDeltaRevocationListAttributeName)
+ {
+ this.ldapDeltaRevocationListAttributeName = ldapDeltaRevocationListAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapAuthorityRevocationListAttributeName
+ * The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>authorityRevocationListIssuerAttributeName</code>.
+ * E.g. if "ou" is used to put information about the issuer of
+ * CRLs, specify "ou".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapAuthorityRevocationListAttributeName(String ldapAuthorityRevocationListAttributeName)
+ {
+ this.ldapAuthorityRevocationListAttributeName = ldapAuthorityRevocationListAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapAttributeCertificateAttributeAttributeName
+ * The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>attributeCertificateAttributeSubjectAttributeName</code>.
+ * E.g. if "cn" is used to put information about the subject of
+ * end attribute certificates, specify "cn".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapAttributeCertificateAttributeAttributeName(String ldapAttributeCertificateAttributeAttributeName)
+ {
+ this.ldapAttributeCertificateAttributeAttributeName = ldapAttributeCertificateAttributeAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapAACertificateAttributeName The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>aACertificateSubjectAttributeName</code>. E.g. if
+ * "ou" is used to put information about the subject of attribute
+ * authority attribute certificates, specify "ou".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapAACertificateAttributeName(String ldapAACertificateAttributeName)
+ {
+ this.ldapAACertificateAttributeName = ldapAACertificateAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapAttributeDescriptorCertificateAttributeName
+ * The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>attributeDescriptorCertificateSubjectAttributeName</code>.
+ * E.g. if "o" is used to put information about the subject of
+ * self signed attribute authority attribute certificates,
+ * specify "o".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapAttributeDescriptorCertificateAttributeName(String ldapAttributeDescriptorCertificateAttributeName)
+ {
+ this.ldapAttributeDescriptorCertificateAttributeName = ldapAttributeDescriptorCertificateAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapAttributeCertificateRevocationListAttributeName
+ * The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>attributeCertificateRevocationListIssuerAttributeName</code>.
+ * E.g. if "ou" is used to put information about the issuer of
+ * CRLs, specify "ou".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapAttributeCertificateRevocationListAttributeName(String ldapAttributeCertificateRevocationListAttributeName)
+ {
+ this.ldapAttributeCertificateRevocationListAttributeName = ldapAttributeCertificateRevocationListAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param ldapAttributeAuthorityRevocationListAttributeName
+ * The attribute name(s) in the LDAP directory where to search for
+ * the attribute value of the specified
+ * <code>attributeAuthorityRevocationListIssuerAttributeName</code>.
+ * E.g. if "ou" is used to put information about the issuer of
+ * CRLs, specify "ou".
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setLdapAttributeAuthorityRevocationListAttributeName(String ldapAttributeAuthorityRevocationListAttributeName)
+ {
+ this.ldapAttributeAuthorityRevocationListAttributeName = ldapAttributeAuthorityRevocationListAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param userCertificateSubjectAttributeName
+ * Attribute(s) in the subject of the certificate which is used
+ * to be searched in the
+ * <code>ldapUserCertificateAttributeName</code>. E.g. the
+ * "cn" attribute of the DN could be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setUserCertificateSubjectAttributeName(String userCertificateSubjectAttributeName)
+ {
+ this.userCertificateSubjectAttributeName = userCertificateSubjectAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param cACertificateSubjectAttributeName
+ * Attribute(s) in the subject of the certificate which is used
+ * to be searched in the
+ * <code>ldapCACertificateAttributeName</code>. E.g. the "ou"
+ * attribute of the DN could be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setCACertificateSubjectAttributeName(String cACertificateSubjectAttributeName)
+ {
+ this.cACertificateSubjectAttributeName = cACertificateSubjectAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param crossCertificateSubjectAttributeName
+ * Attribute(s) in the subject of the cross certificate which is
+ * used to be searched in the
+ * <code>ldapCrossCertificateAttributeName</code>. E.g. the
+ * "o" attribute of the DN may be appropriate.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setCrossCertificateSubjectAttributeName(String crossCertificateSubjectAttributeName)
+ {
+ this.crossCertificateSubjectAttributeName = crossCertificateSubjectAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param certificateRevocationListIssuerAttributeName
+ * Attribute(s) in the issuer of the CRL which is used to be
+ * searched in the
+ * <code>ldapCertificateRevocationListAttributeName</code>.
+ * E.g. the "o" or "ou" attribute may be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setCertificateRevocationListIssuerAttributeName(String certificateRevocationListIssuerAttributeName)
+ {
+ this.certificateRevocationListIssuerAttributeName = certificateRevocationListIssuerAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param deltaRevocationListIssuerAttributeName
+ * Attribute(s) in the issuer of the CRL which is used to be
+ * searched in the
+ * <code>ldapDeltaRevocationListAttributeName</code>. E.g. the
+ * "o" or "ou" attribute may be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setDeltaRevocationListIssuerAttributeName(String deltaRevocationListIssuerAttributeName)
+ {
+ this.deltaRevocationListIssuerAttributeName = deltaRevocationListIssuerAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param authorityRevocationListIssuerAttributeName
+ * Attribute(s) in the issuer of the CRL which is used to be
+ * searched in the
+ * <code>ldapAuthorityRevocationListAttributeName</code>. E.g.
+ * the "o" or "ou" attribute may be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAuthorityRevocationListIssuerAttributeName(String authorityRevocationListIssuerAttributeName)
+ {
+ this.authorityRevocationListIssuerAttributeName = authorityRevocationListIssuerAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param attributeCertificateAttributeSubjectAttributeName
+ * Attribute(s) in the subject of the attribute certificate which
+ * is used to be searched in the
+ * <code>ldapAttributeCertificateAttributeAttributeName</code>.
+ * E.g. the "cn" attribute of the DN could be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAttributeCertificateAttributeSubjectAttributeName(String attributeCertificateAttributeSubjectAttributeName)
+ {
+ this.attributeCertificateAttributeSubjectAttributeName = attributeCertificateAttributeSubjectAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param aACertificateSubjectAttributeName
+ * Attribute(s) in the subject of the attribute certificate which
+ * is used to be searched in the
+ * <code>ldapAACertificateAttributeName</code>. E.g. the "ou"
+ * attribute of the DN could be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAACertificateSubjectAttributeName(String aACertificateSubjectAttributeName)
+ {
+ this.aACertificateSubjectAttributeName = aACertificateSubjectAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param attributeDescriptorCertificateSubjectAttributeName
+ * Attribute(s) in the subject of the attribute certificate which
+ * is used to be searched in the
+ * <code>ldapAttributeDescriptorCertificateAttributeName</code>.
+ * E.g. the "o" attribute of the DN could be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAttributeDescriptorCertificateSubjectAttributeName(String attributeDescriptorCertificateSubjectAttributeName)
+ {
+ this.attributeDescriptorCertificateSubjectAttributeName = attributeDescriptorCertificateSubjectAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param attributeCertificateRevocationListIssuerAttributeName
+ * Attribute(s) in the issuer of the CRL which is used to be
+ * searched in the
+ * <code>ldapAttributeCertificateRevocationListAttributeName</code>.
+ * E.g. the "o" or "ou" attribute may be used
+ * certificate is searched in this LDAP attribute.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAttributeCertificateRevocationListIssuerAttributeName(String attributeCertificateRevocationListIssuerAttributeName)
+ {
+ this.attributeCertificateRevocationListIssuerAttributeName = attributeCertificateRevocationListIssuerAttributeName;
+
+ return this;
+ }
+
+ /**
+ * @param attributeAuthorityRevocationListIssuerAttributeName
+ * Anttribute(s) in the issuer of the CRL which is used to be
+ * searched in the
+ * <code>ldapAttributeAuthorityRevocationListAttributeName</code>.
+ * E.g. the "o" or "ou" attribute may be used.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setAttributeAuthorityRevocationListIssuerAttributeName(String attributeAuthorityRevocationListIssuerAttributeName)
+ {
+ this.attributeAuthorityRevocationListIssuerAttributeName = attributeAuthorityRevocationListIssuerAttributeName;
+
+ return this;
+ }
+
+ /**
+ *
+ * @param searchForSerialNumberIn If not <code>null</code> the serial number of the
+ * certificate is searched in this LDAP attribute.
+ * @throws IllegalArgumentException if a necessary parameter is <code>null</code>.
+ * @return the builder
+ */
+ public Builder setSearchForSerialNumberIn(String searchForSerialNumberIn)
+ {
+ this.searchForSerialNumberIn = searchForSerialNumberIn;
+
+ return this;
+ }
+
+ public X509LDAPCertStoreParameters build()
+ {
+ if (ldapUserCertificateAttributeName == null // migrate to setters
+ || ldapCACertificateAttributeName == null
+ || ldapCrossCertificateAttributeName == null
+ || ldapCertificateRevocationListAttributeName == null
+ || ldapDeltaRevocationListAttributeName == null
+ || ldapAuthorityRevocationListAttributeName == null
+ || ldapAttributeCertificateAttributeAttributeName == null
+ || ldapAACertificateAttributeName == null
+ || ldapAttributeDescriptorCertificateAttributeName == null
+ || ldapAttributeCertificateRevocationListAttributeName == null
+ || ldapAttributeAuthorityRevocationListAttributeName == null
+ || userCertificateSubjectAttributeName == null
+ || cACertificateSubjectAttributeName == null
+ || crossCertificateSubjectAttributeName == null
+ || certificateRevocationListIssuerAttributeName == null
+ || deltaRevocationListIssuerAttributeName == null
+ || authorityRevocationListIssuerAttributeName == null
+ || attributeCertificateAttributeSubjectAttributeName == null
+ || aACertificateSubjectAttributeName == null
+ || attributeDescriptorCertificateSubjectAttributeName == null
+ || attributeCertificateRevocationListIssuerAttributeName == null
+ || attributeAuthorityRevocationListIssuerAttributeName == null)
+ {
+ throw new IllegalArgumentException(
+ "Necessary parameters not specified.");
+ }
+ return new X509LDAPCertStoreParameters(this);
+ }
+ }
+
+
+ private X509LDAPCertStoreParameters(Builder builder)
+ {
+ this.ldapURL = builder.ldapURL;
+ this.baseDN = builder.baseDN;
+
+ this.userCertificateAttribute = builder.userCertificateAttribute;
+ this.cACertificateAttribute = builder.cACertificateAttribute;
+ this.crossCertificateAttribute = builder.crossCertificateAttribute;
+ this.certificateRevocationListAttribute = builder.certificateRevocationListAttribute;
+ this.deltaRevocationListAttribute = builder.deltaRevocationListAttribute;
+ this.authorityRevocationListAttribute = builder.authorityRevocationListAttribute;
+ this.attributeCertificateAttributeAttribute = builder.attributeCertificateAttributeAttribute;
+ this.aACertificateAttribute = builder.aACertificateAttribute;
+ this.attributeDescriptorCertificateAttribute = builder.attributeDescriptorCertificateAttribute;
+ this.attributeCertificateRevocationListAttribute = builder.attributeCertificateRevocationListAttribute;
+ this.attributeAuthorityRevocationListAttribute = builder.attributeAuthorityRevocationListAttribute;
+ this.ldapUserCertificateAttributeName = builder.ldapUserCertificateAttributeName;
+ this.ldapCACertificateAttributeName = builder.ldapCACertificateAttributeName;
+ this.ldapCrossCertificateAttributeName = builder.ldapCrossCertificateAttributeName;
+ this.ldapCertificateRevocationListAttributeName = builder.ldapCertificateRevocationListAttributeName;
+ this.ldapDeltaRevocationListAttributeName = builder.ldapDeltaRevocationListAttributeName;
+ this.ldapAuthorityRevocationListAttributeName = builder.ldapAuthorityRevocationListAttributeName;
+ this.ldapAttributeCertificateAttributeAttributeName = builder.ldapAttributeCertificateAttributeAttributeName;
+ this.ldapAACertificateAttributeName = builder.ldapAACertificateAttributeName;
+ this.ldapAttributeDescriptorCertificateAttributeName = builder.ldapAttributeDescriptorCertificateAttributeName;
+ this.ldapAttributeCertificateRevocationListAttributeName = builder.ldapAttributeCertificateRevocationListAttributeName;
+ this.ldapAttributeAuthorityRevocationListAttributeName = builder.ldapAttributeAuthorityRevocationListAttributeName;
+ this.userCertificateSubjectAttributeName = builder.userCertificateSubjectAttributeName;
+ this.cACertificateSubjectAttributeName = builder.cACertificateSubjectAttributeName;
+ this.crossCertificateSubjectAttributeName = builder.crossCertificateSubjectAttributeName;
+ this.certificateRevocationListIssuerAttributeName = builder.certificateRevocationListIssuerAttributeName;
+ this.deltaRevocationListIssuerAttributeName = builder.deltaRevocationListIssuerAttributeName;
+ this.authorityRevocationListIssuerAttributeName = builder.authorityRevocationListIssuerAttributeName;
+ this.attributeCertificateAttributeSubjectAttributeName = builder.attributeCertificateAttributeSubjectAttributeName;
+ this.aACertificateSubjectAttributeName = builder.aACertificateSubjectAttributeName;
+ this.attributeDescriptorCertificateSubjectAttributeName = builder.attributeDescriptorCertificateSubjectAttributeName;
+ this.attributeCertificateRevocationListIssuerAttributeName = builder.attributeCertificateRevocationListIssuerAttributeName;
+ this.attributeAuthorityRevocationListIssuerAttributeName = builder.attributeAuthorityRevocationListIssuerAttributeName;
+ this.searchForSerialNumberIn = builder.searchForSerialNumberIn;
+ }
+
+ /**
+ * Returns a clone of this object.
+ */
+ public Object clone()
+ {
+ return this;
+ }
+
+ public boolean equal(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof X509LDAPCertStoreParameters))
+ {
+ return false;
+ }
+
+ X509LDAPCertStoreParameters params = (X509LDAPCertStoreParameters)o;
+ return checkField(ldapURL, params.ldapURL)
+ && checkField(baseDN, params.baseDN)
+ && checkField(userCertificateAttribute, params.userCertificateAttribute)
+ && checkField(cACertificateAttribute, params.cACertificateAttribute)
+ && checkField(crossCertificateAttribute, params.crossCertificateAttribute)
+ && checkField(certificateRevocationListAttribute, params.certificateRevocationListAttribute)
+ && checkField(deltaRevocationListAttribute, params.deltaRevocationListAttribute)
+ && checkField(authorityRevocationListAttribute, params.authorityRevocationListAttribute)
+ && checkField(attributeCertificateAttributeAttribute, params.attributeCertificateAttributeAttribute)
+ && checkField(aACertificateAttribute, params.aACertificateAttribute)
+ && checkField(attributeDescriptorCertificateAttribute, params.attributeDescriptorCertificateAttribute)
+ && checkField(attributeCertificateRevocationListAttribute, params.attributeCertificateRevocationListAttribute)
+ && checkField(attributeAuthorityRevocationListAttribute, params.attributeAuthorityRevocationListAttribute)
+ && checkField(ldapUserCertificateAttributeName, params.ldapUserCertificateAttributeName)
+ && checkField(ldapCACertificateAttributeName, params.ldapCACertificateAttributeName)
+ && checkField(ldapCrossCertificateAttributeName, params.ldapCrossCertificateAttributeName)
+ && checkField(ldapCertificateRevocationListAttributeName, params.ldapCertificateRevocationListAttributeName)
+ && checkField(ldapDeltaRevocationListAttributeName, params.ldapDeltaRevocationListAttributeName)
+ && checkField(ldapAuthorityRevocationListAttributeName, params.ldapAuthorityRevocationListAttributeName)
+ && checkField(ldapAttributeCertificateAttributeAttributeName, params.ldapAttributeCertificateAttributeAttributeName)
+ && checkField(ldapAACertificateAttributeName, params.ldapAACertificateAttributeName)
+ && checkField(ldapAttributeDescriptorCertificateAttributeName, params.ldapAttributeDescriptorCertificateAttributeName)
+ && checkField(ldapAttributeCertificateRevocationListAttributeName, params.ldapAttributeCertificateRevocationListAttributeName)
+ && checkField(ldapAttributeAuthorityRevocationListAttributeName, params.ldapAttributeAuthorityRevocationListAttributeName)
+ && checkField(userCertificateSubjectAttributeName, params.userCertificateSubjectAttributeName)
+ && checkField(cACertificateSubjectAttributeName, params.cACertificateSubjectAttributeName)
+ && checkField(crossCertificateSubjectAttributeName, params.crossCertificateSubjectAttributeName)
+ && checkField(certificateRevocationListIssuerAttributeName, params.certificateRevocationListIssuerAttributeName)
+ && checkField(deltaRevocationListIssuerAttributeName, params.deltaRevocationListIssuerAttributeName)
+ && checkField(authorityRevocationListIssuerAttributeName, params.authorityRevocationListIssuerAttributeName)
+ && checkField(attributeCertificateAttributeSubjectAttributeName, params.attributeCertificateAttributeSubjectAttributeName)
+ && checkField(aACertificateSubjectAttributeName, params.aACertificateSubjectAttributeName)
+ && checkField(attributeDescriptorCertificateSubjectAttributeName, params.attributeDescriptorCertificateSubjectAttributeName)
+ && checkField(attributeCertificateRevocationListIssuerAttributeName, params.attributeCertificateRevocationListIssuerAttributeName)
+ && checkField(attributeAuthorityRevocationListIssuerAttributeName, params.attributeAuthorityRevocationListIssuerAttributeName)
+ && checkField(searchForSerialNumberIn, params.searchForSerialNumberIn);
+ }
+
+ private boolean checkField(Object o1, Object o2)
+ {
+ if (o1 == o2)
+ {
+ return true;
+ }
+
+ if (o1 == null)
+ {
+ return false;
+ }
+
+ return o1.equals(o2);
+ }
+
+ public int hashCode()
+ {
+ int hash = 0;
+
+ hash = addHashCode(hash, userCertificateAttribute);
+ hash = addHashCode(hash, cACertificateAttribute);
+ hash = addHashCode(hash, crossCertificateAttribute);
+ hash = addHashCode(hash, certificateRevocationListAttribute);
+ hash = addHashCode(hash, deltaRevocationListAttribute);
+ hash = addHashCode(hash, authorityRevocationListAttribute);
+ hash = addHashCode(hash, attributeCertificateAttributeAttribute);
+ hash = addHashCode(hash, aACertificateAttribute);
+ hash = addHashCode(hash, attributeDescriptorCertificateAttribute);
+ hash = addHashCode(hash, attributeCertificateRevocationListAttribute);
+ hash = addHashCode(hash, attributeAuthorityRevocationListAttribute);
+ hash = addHashCode(hash, ldapUserCertificateAttributeName);
+ hash = addHashCode(hash, ldapCACertificateAttributeName);
+ hash = addHashCode(hash, ldapCrossCertificateAttributeName);
+ hash = addHashCode(hash, ldapCertificateRevocationListAttributeName);
+ hash = addHashCode(hash, ldapDeltaRevocationListAttributeName);
+ hash = addHashCode(hash, ldapAuthorityRevocationListAttributeName);
+ hash = addHashCode(hash, ldapAttributeCertificateAttributeAttributeName);
+ hash = addHashCode(hash, ldapAACertificateAttributeName);
+ hash = addHashCode(hash, ldapAttributeDescriptorCertificateAttributeName);
+ hash = addHashCode(hash, ldapAttributeCertificateRevocationListAttributeName);
+ hash = addHashCode(hash, ldapAttributeAuthorityRevocationListAttributeName);
+ hash = addHashCode(hash, userCertificateSubjectAttributeName);
+ hash = addHashCode(hash, cACertificateSubjectAttributeName);
+ hash = addHashCode(hash, crossCertificateSubjectAttributeName);
+ hash = addHashCode(hash, certificateRevocationListIssuerAttributeName);
+ hash = addHashCode(hash, deltaRevocationListIssuerAttributeName);
+ hash = addHashCode(hash, authorityRevocationListIssuerAttributeName);
+ hash = addHashCode(hash, attributeCertificateAttributeSubjectAttributeName);
+ hash = addHashCode(hash, aACertificateSubjectAttributeName);
+ hash = addHashCode(hash, attributeDescriptorCertificateSubjectAttributeName);
+ hash = addHashCode(hash, attributeCertificateRevocationListIssuerAttributeName);
+ hash = addHashCode(hash, attributeAuthorityRevocationListIssuerAttributeName);
+ hash = addHashCode(hash, searchForSerialNumberIn);
+
+ return hash;
+ }
+
+ private int addHashCode(int hashCode, Object o)
+ {
+ return (hashCode * 29) + (o == null ? 0 : o.hashCode());
+ }
+
+ /**
+ * @return Returns the aACertificateAttribute.
+ */
+ public String getAACertificateAttribute()
+ {
+ return aACertificateAttribute;
+ }
+
+ /**
+ * @return Returns the aACertificateSubjectAttributeName.
+ */
+ public String getAACertificateSubjectAttributeName()
+ {
+ return aACertificateSubjectAttributeName;
+ }
+
+ /**
+ * @return Returns the attributeAuthorityRevocationListAttribute.
+ */
+ public String getAttributeAuthorityRevocationListAttribute()
+ {
+ return attributeAuthorityRevocationListAttribute;
+ }
+
+ /**
+ * @return Returns the attributeAuthorityRevocationListIssuerAttributeName.
+ */
+ public String getAttributeAuthorityRevocationListIssuerAttributeName()
+ {
+ return attributeAuthorityRevocationListIssuerAttributeName;
+ }
+
+ /**
+ * @return Returns the attributeCertificateAttributeAttribute.
+ */
+ public String getAttributeCertificateAttributeAttribute()
+ {
+ return attributeCertificateAttributeAttribute;
+ }
+
+ /**
+ * @return Returns the attributeCertificateAttributeSubjectAttributeName.
+ */
+ public String getAttributeCertificateAttributeSubjectAttributeName()
+ {
+ return attributeCertificateAttributeSubjectAttributeName;
+ }
+
+ /**
+ * @return Returns the attributeCertificateRevocationListAttribute.
+ */
+ public String getAttributeCertificateRevocationListAttribute()
+ {
+ return attributeCertificateRevocationListAttribute;
+ }
+
+ /**
+ * @return Returns the
+ * attributeCertificateRevocationListIssuerAttributeName.
+ */
+ public String getAttributeCertificateRevocationListIssuerAttributeName()
+ {
+ return attributeCertificateRevocationListIssuerAttributeName;
+ }
+
+ /**
+ * @return Returns the attributeDescriptorCertificateAttribute.
+ */
+ public String getAttributeDescriptorCertificateAttribute()
+ {
+ return attributeDescriptorCertificateAttribute;
+ }
+
+ /**
+ * @return Returns the attributeDescriptorCertificateSubjectAttributeName.
+ */
+ public String getAttributeDescriptorCertificateSubjectAttributeName()
+ {
+ return attributeDescriptorCertificateSubjectAttributeName;
+ }
+
+ /**
+ * @return Returns the authorityRevocationListAttribute.
+ */
+ public String getAuthorityRevocationListAttribute()
+ {
+ return authorityRevocationListAttribute;
+ }
+
+ /**
+ * @return Returns the authorityRevocationListIssuerAttributeName.
+ */
+ public String getAuthorityRevocationListIssuerAttributeName()
+ {
+ return authorityRevocationListIssuerAttributeName;
+ }
+
+ /**
+ * @return Returns the baseDN.
+ */
+ public String getBaseDN()
+ {
+ return baseDN;
+ }
+
+ /**
+ * @return Returns the cACertificateAttribute.
+ */
+ public String getCACertificateAttribute()
+ {
+ return cACertificateAttribute;
+ }
+
+ /**
+ * @return Returns the cACertificateSubjectAttributeName.
+ */
+ public String getCACertificateSubjectAttributeName()
+ {
+ return cACertificateSubjectAttributeName;
+ }
+
+ /**
+ * @return Returns the certificateRevocationListAttribute.
+ */
+ public String getCertificateRevocationListAttribute()
+ {
+ return certificateRevocationListAttribute;
+ }
+
+ /**
+ * @return Returns the certificateRevocationListIssuerAttributeName.
+ */
+ public String getCertificateRevocationListIssuerAttributeName()
+ {
+ return certificateRevocationListIssuerAttributeName;
+ }
+
+ /**
+ * @return Returns the crossCertificateAttribute.
+ */
+ public String getCrossCertificateAttribute()
+ {
+ return crossCertificateAttribute;
+ }
+
+ /**
+ * @return Returns the crossCertificateSubjectAttributeName.
+ */
+ public String getCrossCertificateSubjectAttributeName()
+ {
+ return crossCertificateSubjectAttributeName;
+ }
+
+ /**
+ * @return Returns the deltaRevocationListAttribute.
+ */
+ public String getDeltaRevocationListAttribute()
+ {
+ return deltaRevocationListAttribute;
+ }
+
+ /**
+ * @return Returns the deltaRevocationListIssuerAttributeName.
+ */
+ public String getDeltaRevocationListIssuerAttributeName()
+ {
+ return deltaRevocationListIssuerAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapAACertificateAttributeName.
+ */
+ public String getLdapAACertificateAttributeName()
+ {
+ return ldapAACertificateAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapAttributeAuthorityRevocationListAttributeName.
+ */
+ public String getLdapAttributeAuthorityRevocationListAttributeName()
+ {
+ return ldapAttributeAuthorityRevocationListAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapAttributeCertificateAttributeAttributeName.
+ */
+ public String getLdapAttributeCertificateAttributeAttributeName()
+ {
+ return ldapAttributeCertificateAttributeAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapAttributeCertificateRevocationListAttributeName.
+ */
+ public String getLdapAttributeCertificateRevocationListAttributeName()
+ {
+ return ldapAttributeCertificateRevocationListAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapAttributeDescriptorCertificateAttributeName.
+ */
+ public String getLdapAttributeDescriptorCertificateAttributeName()
+ {
+ return ldapAttributeDescriptorCertificateAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapAuthorityRevocationListAttributeName.
+ */
+ public String getLdapAuthorityRevocationListAttributeName()
+ {
+ return ldapAuthorityRevocationListAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapCACertificateAttributeName.
+ */
+ public String getLdapCACertificateAttributeName()
+ {
+ return ldapCACertificateAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapCertificateRevocationListAttributeName.
+ */
+ public String getLdapCertificateRevocationListAttributeName()
+ {
+ return ldapCertificateRevocationListAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapCrossCertificateAttributeName.
+ */
+ public String getLdapCrossCertificateAttributeName()
+ {
+ return ldapCrossCertificateAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapDeltaRevocationListAttributeName.
+ */
+ public String getLdapDeltaRevocationListAttributeName()
+ {
+ return ldapDeltaRevocationListAttributeName;
+ }
+
+ /**
+ * @return Returns the ldapURL.
+ */
+ public String getLdapURL()
+ {
+ return ldapURL;
+ }
+
+ /**
+ * @return Returns the ldapUserCertificateAttributeName.
+ */
+ public String getLdapUserCertificateAttributeName()
+ {
+ return ldapUserCertificateAttributeName;
+ }
+
+ /**
+ * @return Returns the searchForSerialNumberIn.
+ */
+ public String getSearchForSerialNumberIn()
+ {
+ return searchForSerialNumberIn;
+ }
+
+ /**
+ * @return Returns the userCertificateAttribute.
+ */
+ public String getUserCertificateAttribute()
+ {
+ return userCertificateAttribute;
+ }
+
+ /**
+ * @return Returns the userCertificateSubjectAttributeName.
+ */
+ public String getUserCertificateSubjectAttributeName()
+ {
+ return userCertificateSubjectAttributeName;
+ }
+
+ public static X509LDAPCertStoreParameters getInstance(LDAPCertStoreParameters params)
+ {
+ String server = "ldap://" + params.getServerName() + ":" + params.getPort();
+ X509LDAPCertStoreParameters _params = new Builder(server, "").build();
+ return _params;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509Principal.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509Principal.java
new file mode 100644
index 000000000..f7a96895a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/X509Principal.java
@@ -0,0 +1,165 @@
+package org.spongycastle.jce;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.X509Name;
+
+/**
+ * a general extension of X509Name with a couple of extra methods and
+ * constructors.
+ * <p>
+ * Objects of this type can be created from certificates and CRLs using the
+ * PrincipalUtil class.
+ * </p>
+ * @see org.spongycastle.jce.PrincipalUtil
+ * @deprecated use the X500Name class.
+ */
+public class X509Principal
+ extends X509Name
+ implements Principal
+{
+ private static ASN1Sequence readSequence(
+ ASN1InputStream aIn)
+ throws IOException
+ {
+ try
+ {
+ return ASN1Sequence.getInstance(aIn.readObject());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("not an ASN.1 Sequence: " + e);
+ }
+ }
+
+ /**
+ * Constructor from an encoded byte array.
+ */
+ public X509Principal(
+ byte[] bytes)
+ throws IOException
+ {
+ super(readSequence(new ASN1InputStream(bytes)));
+ }
+
+ /**
+ * Constructor from an X509Name object.
+ */
+ public X509Principal(
+ X509Name name)
+ {
+ super((ASN1Sequence)name.toASN1Primitive());
+ }
+
+ /**
+ * Constructor from an X509Name object.
+ */
+ public X509Principal(
+ X500Name name)
+ {
+ super((ASN1Sequence)name.toASN1Primitive());
+ }
+
+ /**
+ * constructor from a table of attributes.
+ * <p>
+ * it's is assumed the table contains OID/String pairs.
+ */
+ public X509Principal(
+ Hashtable attributes)
+ {
+ super(attributes);
+ }
+
+ /**
+ * constructor from a table of attributes and a vector giving the
+ * specific ordering required for encoding or conversion to a string.
+ * <p>
+ * it's is assumed the table contains OID/String pairs.
+ */
+ public X509Principal(
+ Vector ordering,
+ Hashtable attributes)
+ {
+ super(ordering, attributes);
+ }
+
+ /**
+ * constructor from a vector of attribute values and a vector of OIDs.
+ */
+ public X509Principal(
+ Vector oids,
+ Vector values)
+ {
+ super(oids, values);
+ }
+
+ /**
+ * takes an X509 dir name as a string of the format "C=AU,ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes.
+ */
+ public X509Principal(
+ String dirName)
+ {
+ super(dirName);
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU,ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes. If reverse
+ * is false the dir name will be encoded in the order of the (name, value) pairs
+ * presented, otherwise the encoding will start with the last (name, value) pair
+ * and work back.
+ */
+ public X509Principal(
+ boolean reverse,
+ String dirName)
+ {
+ super(reverse, dirName);
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes. lookUp
+ * should provide a table of lookups, indexed by lowercase only strings and
+ * yielding a DERObjectIdentifier, other than that OID. and numeric oids
+ * will be processed automatically.
+ * <p>
+ * If reverse is true, create the encoded version of the sequence starting
+ * from the last element in the string.
+ */
+ public X509Principal(
+ boolean reverse,
+ Hashtable lookUp,
+ String dirName)
+ {
+ super(reverse, lookUp, dirName);
+ }
+
+ public String getName()
+ {
+ return this.toString();
+ }
+
+ /**
+ * return a DER encoded byte array representing this object
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ return this.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/examples/PKCS12Example.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/examples/PKCS12Example.java
new file mode 100644
index 000000000..6daf57bda
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/examples/PKCS12Example.java
@@ -0,0 +1,379 @@
+package org.spongycastle.jce.examples;
+
+import java.io.FileOutputStream;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.spongycastle.asn1.DERBMPString;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.x509.X509V1CertificateGenerator;
+import org.spongycastle.x509.X509V3CertificateGenerator;
+import org.spongycastle.x509.extension.AuthorityKeyIdentifierStructure;
+import org.spongycastle.x509.extension.SubjectKeyIdentifierStructure;
+
+/**
+ * Example of how to set up a certificiate chain and a PKCS 12 store for
+ * a private individual - obviously you'll need to generate your own keys,
+ * and you may need to add a NetscapeCertType extension or add a key
+ * usage extension depending on your application, but you should get the
+ * idea! As always this is just an example...
+ */
+public class PKCS12Example
+{
+ static char[] passwd = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' };
+
+ static X509V1CertificateGenerator v1CertGen = new X509V1CertificateGenerator();
+ static X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
+
+ /**
+ * we generate the CA's certificate
+ */
+ public static Certificate createMasterCert(
+ PublicKey pubKey,
+ PrivateKey privKey)
+ throws Exception
+ {
+ //
+ // signers name
+ //
+ String issuer = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+ //
+ // subjects name - the same as we are self signed.
+ //
+ String subject = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+ //
+ // create the certificate - version 1
+ //
+
+ v1CertGen.setSerialNumber(BigInteger.valueOf(1));
+ v1CertGen.setIssuerDN(new X509Principal(issuer));
+ v1CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
+ v1CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)));
+ v1CertGen.setSubjectDN(new X509Principal(subject));
+ v1CertGen.setPublicKey(pubKey);
+ v1CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ X509Certificate cert = v1CertGen.generate(privKey);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ //
+ // this is actually optional - but if you want to have control
+ // over setting the friendly name this is the way to do it...
+ //
+ bagAttr.setBagAttribute(
+ PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
+ new DERBMPString("Bouncy Primary Certificate"));
+
+ return cert;
+ }
+
+ /**
+ * we generate an intermediate certificate signed by our CA
+ */
+ public static Certificate createIntermediateCert(
+ PublicKey pubKey,
+ PrivateKey caPrivKey,
+ X509Certificate caCert)
+ throws Exception
+ {
+ //
+ // subject name table.
+ //
+ Hashtable attrs = new Hashtable();
+ Vector order = new Vector();
+
+ attrs.put(X509Principal.C, "AU");
+ attrs.put(X509Principal.O, "The Legion of the Bouncy Castle");
+ attrs.put(X509Principal.OU, "Bouncy Intermediate Certificate");
+ attrs.put(X509Principal.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ order.addElement(X509Principal.C);
+ order.addElement(X509Principal.O);
+ order.addElement(X509Principal.OU);
+ order.addElement(X509Principal.EmailAddress);
+
+ //
+ // create the certificate - version 3
+ //
+ v3CertGen.reset();
+
+ v3CertGen.setSerialNumber(BigInteger.valueOf(2));
+ v3CertGen.setIssuerDN(PrincipalUtil.getSubjectX509Principal(caCert));
+ v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
+ v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)));
+ v3CertGen.setSubjectDN(new X509Principal(order, attrs));
+ v3CertGen.setPublicKey(pubKey);
+ v3CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ //
+ // extensions
+ //
+ v3CertGen.addExtension(
+ X509Extensions.SubjectKeyIdentifier,
+ false,
+ new SubjectKeyIdentifierStructure(pubKey));
+
+ v3CertGen.addExtension(
+ X509Extensions.AuthorityKeyIdentifier,
+ false,
+ new AuthorityKeyIdentifierStructure(caCert));
+
+ v3CertGen.addExtension(
+ X509Extensions.BasicConstraints,
+ true,
+ new BasicConstraints(0));
+
+ X509Certificate cert = v3CertGen.generate(caPrivKey);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(caCert.getPublicKey());
+
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ //
+ // this is actually optional - but if you want to have control
+ // over setting the friendly name this is the way to do it...
+ //
+ bagAttr.setBagAttribute(
+ PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
+ new DERBMPString("Bouncy Intermediate Certificate"));
+
+ return cert;
+ }
+
+ /**
+ * we generate a certificate signed by our CA's intermediate certficate
+ */
+ public static Certificate createCert(
+ PublicKey pubKey,
+ PrivateKey caPrivKey,
+ PublicKey caPubKey)
+ throws Exception
+ {
+ //
+ // signers name table.
+ //
+ Hashtable sAttrs = new Hashtable();
+ Vector sOrder = new Vector();
+
+ sAttrs.put(X509Principal.C, "AU");
+ sAttrs.put(X509Principal.O, "The Legion of the Bouncy Castle");
+ sAttrs.put(X509Principal.OU, "Bouncy Intermediate Certificate");
+ sAttrs.put(X509Principal.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ sOrder.addElement(X509Principal.C);
+ sOrder.addElement(X509Principal.O);
+ sOrder.addElement(X509Principal.OU);
+ sOrder.addElement(X509Principal.EmailAddress);
+
+ //
+ // subjects name table.
+ //
+ Hashtable attrs = new Hashtable();
+ Vector order = new Vector();
+
+ attrs.put(X509Principal.C, "AU");
+ attrs.put(X509Principal.O, "The Legion of the Bouncy Castle");
+ attrs.put(X509Principal.L, "Melbourne");
+ attrs.put(X509Principal.CN, "Eric H. Echidna");
+ attrs.put(X509Principal.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ order.addElement(X509Principal.C);
+ order.addElement(X509Principal.O);
+ order.addElement(X509Principal.L);
+ order.addElement(X509Principal.CN);
+ order.addElement(X509Principal.EmailAddress);
+
+ //
+ // create the certificate - version 3
+ //
+ v3CertGen.reset();
+
+ v3CertGen.setSerialNumber(BigInteger.valueOf(3));
+ v3CertGen.setIssuerDN(new X509Principal(sOrder, sAttrs));
+ v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
+ v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)));
+ v3CertGen.setSubjectDN(new X509Principal(order, attrs));
+ v3CertGen.setPublicKey(pubKey);
+ v3CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ //
+ // add the extensions
+ //
+ v3CertGen.addExtension(
+ X509Extensions.SubjectKeyIdentifier,
+ false,
+ new SubjectKeyIdentifierStructure(pubKey));
+
+ v3CertGen.addExtension(
+ X509Extensions.AuthorityKeyIdentifier,
+ false,
+ new AuthorityKeyIdentifierStructure(caPubKey));
+
+ X509Certificate cert = v3CertGen.generate(caPrivKey);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(caPubKey);
+
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ //
+ // this is also optional - in the sense that if you leave this
+ // out the keystore will add it automatically, note though that
+ // for the browser to recognise the associated private key this
+ // you should at least use the pkcs_9_localKeyId OID and set it
+ // to the same as you do for the private key's localKeyId.
+ //
+ bagAttr.setBagAttribute(
+ PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
+ new DERBMPString("Eric's Key"));
+ bagAttr.setBagAttribute(
+ PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
+ new SubjectKeyIdentifierStructure(pubKey));
+
+ return cert;
+ }
+
+ public static void main(
+ String[] args)
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ //
+ // personal keys
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16),
+ new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+ new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+ new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+ new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+ new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+ new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+ //
+ // intermediate keys.
+ //
+ RSAPublicKeySpec intPubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
+ new BigInteger("ffff", 16));
+
+
+ RSAPrivateCrtKeySpec intPrivKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
+ new BigInteger("ffff", 16),
+ new BigInteger("7deb1b194a85bcfd29cf871411468adbc987650903e3bacc8338c449ca7b32efd39ffc33bc84412fcd7df18d23ce9d7c25ea910b1ae9985373e0273b4dca7f2e0db3b7314056ac67fd277f8f89cf2fd73c34c6ca69f9ba477143d2b0e2445548aa0b4a8473095182631da46844c356f5e5c7522eb54b5a33f11d730ead9c0cff", 16),
+ new BigInteger("ef4cede573cea47f83699b814de4302edb60eefe426c52e17bd7870ec7c6b7a24fe55282ebb73775f369157726fcfb988def2b40350bdca9e5b418340288f649", 16),
+ new BigInteger("97c7737d1b9a0088c3c7b528539247fd2a1593e7e01cef18848755be82f4a45aa093276cb0cbf118cb41117540a78f3fc471ba5d69f0042274defc9161265721", 16),
+ new BigInteger("6c641094e24d172728b8da3c2777e69adfd0839085be7e38c7c4a2dd00b1ae969f2ec9d23e7e37090fcd449a40af0ed463fe1c612d6810d6b4f58b7bfa31eb5f", 16),
+ new BigInteger("70b7123e8e69dfa76feb1236d0a686144b00e9232ed52b73847e74ef3af71fb45ccb24261f40d27f98101e230cf27b977a5d5f1f15f6cf48d5cb1da2a3a3b87f", 16),
+ new BigInteger("e38f5750d97e270996a286df2e653fd26c242106436f5bab0f4c7a9e654ce02665d5a281f2c412456f2d1fa26586ef04a9adac9004ca7f913162cb28e13bf40d", 16));
+
+ //
+ // ca keys
+ //
+ RSAPublicKeySpec caPubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeySpec caPrivKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+ new BigInteger("11", 16),
+ new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16),
+ new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16),
+ new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16),
+ new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16),
+ new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16),
+ new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16));
+
+
+
+ //
+ // set up the keys
+ //
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+ PrivateKey caPrivKey = fact.generatePrivate(caPrivKeySpec);
+ PublicKey caPubKey = fact.generatePublic(caPubKeySpec);
+ PrivateKey intPrivKey = fact.generatePrivate(intPrivKeySpec);
+ PublicKey intPubKey = fact.generatePublic(intPubKeySpec);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ Certificate[] chain = new Certificate[3];
+
+ chain[2] = createMasterCert(caPubKey, caPrivKey);
+ chain[1] = createIntermediateCert(intPubKey, caPrivKey, (X509Certificate)chain[2]);
+ chain[0] = createCert(pubKey, intPrivKey, intPubKey);
+
+ //
+ // add the friendly name for the private key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+
+ //
+ // this is also optional - in the sense that if you leave this
+ // out the keystore will add it automatically, note though that
+ // for the browser to recognise which certificate the private key
+ // is associated with you should at least use the pkcs_9_localKeyId
+ // OID and set it to the same as you do for the private key's
+ // corresponding certificate.
+ //
+ bagAttr.setBagAttribute(
+ PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
+ new DERBMPString("Eric's Key"));
+ bagAttr.setBagAttribute(
+ PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
+ new SubjectKeyIdentifierStructure(pubKey));
+
+ //
+ // store the key and the certificate chain
+ //
+ KeyStore store = KeyStore.getInstance("PKCS12", "SC");
+
+ store.load(null, null);
+
+ //
+ // if you haven't set the friendly name and local key id above
+ // the name below will be the name of the key
+ //
+ store.setKeyEntry("Eric's Key", privKey, null, chain);
+
+ FileOutputStream fOut = new FileOutputStream("id.p12");
+
+ store.store(fOut, passwd);
+
+ fOut.close();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertPathBuilderException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertPathBuilderException.java
new file mode 100644
index 000000000..65c0e4c4f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertPathBuilderException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.jce.exception;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilderException;
+
+public class ExtCertPathBuilderException
+ extends CertPathBuilderException
+ implements ExtException
+{
+ private Throwable cause;
+
+ public ExtCertPathBuilderException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathBuilderException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertPathValidatorException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertPathValidatorException.java
new file mode 100644
index 000000000..da9003aab
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertPathValidatorException.java
@@ -0,0 +1,30 @@
+package org.spongycastle.jce.exception;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+
+public class ExtCertPathValidatorException
+ extends CertPathValidatorException
+ implements ExtException
+{
+
+ private Throwable cause;
+
+ public ExtCertPathValidatorException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathValidatorException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause, certPath, index);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertificateEncodingException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertificateEncodingException.java
new file mode 100644
index 000000000..210e49e44
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtCertificateEncodingException.java
@@ -0,0 +1,21 @@
+package org.spongycastle.jce.exception;
+
+import java.security.cert.CertificateEncodingException;
+
+public class ExtCertificateEncodingException
+ extends CertificateEncodingException
+ implements ExtException
+{
+ private Throwable cause;
+
+ public ExtCertificateEncodingException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtException.java
new file mode 100644
index 000000000..ea538d13f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtException.java
@@ -0,0 +1,21 @@
+package org.spongycastle.jce.exception;
+
+/**
+ *
+ * This is an extended exception. Java before version 1.4 did not offer the
+ * possibility the attach a cause to an exception. The cause of an exception is
+ * the <code>Throwable</code> object which was thrown and caused the
+ * exception. This interface must be implemented by all exceptions to accomplish
+ * this additional functionality.
+ *
+ */
+public interface ExtException
+{
+
+ /**
+ * Returns the cause of the exception.
+ *
+ * @return The cause of the exception.
+ */
+ Throwable getCause();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtIOException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtIOException.java
new file mode 100644
index 000000000..38bea1385
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/exception/ExtIOException.java
@@ -0,0 +1,21 @@
+package org.spongycastle.jce.exception;
+
+import java.io.IOException;
+
+public class ExtIOException
+ extends IOException
+ implements ExtException
+{
+ private Throwable cause;
+
+ public ExtIOException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/BCKeyStore.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/BCKeyStore.java
new file mode 100644
index 000000000..1b6eede33
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/BCKeyStore.java
@@ -0,0 +1,14 @@
+package org.spongycastle.jce.interfaces;
+
+import java.security.SecureRandom;
+
+/**
+ * all BC provider keystores implement this interface.
+ */
+public interface BCKeyStore
+{
+ /**
+ * set the random source for the key store
+ */
+ public void setRandom(SecureRandom random);
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECKey.java
new file mode 100644
index 000000000..b463c11d9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECKey.java
@@ -0,0 +1,15 @@
+package org.spongycastle.jce.interfaces;
+
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+/**
+ * generic interface for an Elliptic Curve Key.
+ */
+public interface ECKey
+{
+ /**
+ * return a parameter specification representing the EC domain parameters
+ * for the key.
+ */
+ public ECParameterSpec getParameters();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPointEncoder.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPointEncoder.java
new file mode 100644
index 000000000..4123d6574
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPointEncoder.java
@@ -0,0 +1,20 @@
+package org.spongycastle.jce.interfaces;
+
+/**
+ * All BC elliptic curve keys implement this interface. You need to
+ * cast the key to get access to it.
+ * <p>
+ * By default BC keys produce encodings without point compression,
+ * to turn this on call setPointFormat() with "COMPRESSED".
+ */
+public interface ECPointEncoder
+{
+ /**
+ * Set the formatting for encoding of points. If the String "UNCOMPRESSED" is passed
+ * in point compression will not be used. If the String "COMPRESSED" is passed point
+ * compression will be used. The default is "UNCOMPRESSED".
+ *
+ * @param style the style to use.
+ */
+ public void setPointFormat(String style);
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPrivateKey.java
new file mode 100644
index 000000000..235664347
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPrivateKey.java
@@ -0,0 +1,16 @@
+package org.spongycastle.jce.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * interface for Elliptic Curve Private keys.
+ */
+public interface ECPrivateKey
+ extends ECKey, PrivateKey
+{
+ /**
+ * return the private value D.
+ */
+ public BigInteger getD();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPublicKey.java
new file mode 100644
index 000000000..1f4358255
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ECPublicKey.java
@@ -0,0 +1,17 @@
+package org.spongycastle.jce.interfaces;
+
+import java.security.PublicKey;
+
+import org.spongycastle.math.ec.ECPoint;
+
+/**
+ * interface for elliptic curve public keys.
+ */
+public interface ECPublicKey
+ extends ECKey, PublicKey
+{
+ /**
+ * return the public point Q
+ */
+ public ECPoint getQ();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalKey.java
new file mode 100644
index 000000000..eb3154994
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalKey.java
@@ -0,0 +1,8 @@
+package org.spongycastle.jce.interfaces;
+
+import org.spongycastle.jce.spec.ElGamalParameterSpec;
+
+public interface ElGamalKey
+{
+ public ElGamalParameterSpec getParameters();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalPrivateKey.java
new file mode 100644
index 000000000..28d2f9673
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalPrivateKey.java
@@ -0,0 +1,10 @@
+package org.spongycastle.jce.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+public interface ElGamalPrivateKey
+ extends ElGamalKey, PrivateKey
+{
+ public BigInteger getX();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalPublicKey.java
new file mode 100644
index 000000000..e5ec01c29
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/ElGamalPublicKey.java
@@ -0,0 +1,10 @@
+package org.spongycastle.jce.interfaces;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+public interface ElGamalPublicKey
+ extends ElGamalKey, PublicKey
+{
+ public BigInteger getY();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410Key.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410Key.java
new file mode 100644
index 000000000..f1a03f9f7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410Key.java
@@ -0,0 +1,11 @@
+package org.spongycastle.jce.interfaces;
+
+/**
+ * Main interface for a GOST 3410-94 key.
+ */
+public interface GOST3410Key
+{
+
+ public GOST3410Params getParameters();
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410Params.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410Params.java
new file mode 100644
index 000000000..5707a159d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410Params.java
@@ -0,0 +1,15 @@
+package org.spongycastle.jce.interfaces;
+
+import org.spongycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+
+public interface GOST3410Params
+{
+
+ public String getPublicKeyParamSetOID();
+
+ public String getDigestParamSetOID();
+
+ public String getEncryptionParamSetOID();
+
+ public GOST3410PublicKeyParameterSetSpec getPublicKeyParameters();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410PrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410PrivateKey.java
new file mode 100644
index 000000000..867a0fee0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410PrivateKey.java
@@ -0,0 +1,9 @@
+package org.spongycastle.jce.interfaces;
+
+import java.math.BigInteger;
+
+public interface GOST3410PrivateKey extends GOST3410Key, java.security.PrivateKey
+{
+
+ public BigInteger getX();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410PublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410PublicKey.java
new file mode 100644
index 000000000..49d5efd1c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/GOST3410PublicKey.java
@@ -0,0 +1,10 @@
+package org.spongycastle.jce.interfaces;
+
+import java.security.PublicKey;
+import java.math.BigInteger;
+
+public interface GOST3410PublicKey extends GOST3410Key, PublicKey
+{
+
+ public BigInteger getY();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/IESKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/IESKey.java
new file mode 100644
index 000000000..91aebd6ce
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/IESKey.java
@@ -0,0 +1,22 @@
+package org.spongycastle.jce.interfaces;
+
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * key pair for use with an integrated encryptor
+ */
+public interface IESKey
+ extends Key
+{
+ /**
+ * return the intended recipient's/sender's public key.
+ */
+ public PublicKey getPublic();
+
+ /**
+ * return the local private key.
+ */
+ public PrivateKey getPrivate();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/MQVPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/MQVPrivateKey.java
new file mode 100644
index 000000000..283633865
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/MQVPrivateKey.java
@@ -0,0 +1,27 @@
+package org.spongycastle.jce.interfaces;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * Static/ephemeral private key (pair) for use with ECMQV key agreement
+ * (Optionally provides the ephemeral public key)
+ */
+public interface MQVPrivateKey
+ extends PrivateKey
+{
+ /**
+ * return the static private key.
+ */
+ PrivateKey getStaticPrivateKey();
+
+ /**
+ * return the ephemeral private key.
+ */
+ PrivateKey getEphemeralPrivateKey();
+
+ /**
+ * return the ephemeral public key (may be null).
+ */
+ PublicKey getEphemeralPublicKey();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/MQVPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/MQVPublicKey.java
new file mode 100644
index 000000000..a0ff3a328
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/MQVPublicKey.java
@@ -0,0 +1,20 @@
+package org.spongycastle.jce.interfaces;
+
+import java.security.PublicKey;
+
+/**
+ * Static/ephemeral public key pair for use with ECMQV key agreement
+ */
+public interface MQVPublicKey
+ extends PublicKey
+{
+ /**
+ * return the static public key.
+ */
+ PublicKey getStaticKey();
+
+ /**
+ * return the ephemeral public key.
+ */
+ PublicKey getEphemeralKey();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/PKCS12BagAttributeCarrier.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
new file mode 100644
index 000000000..fe3a0cb62
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
@@ -0,0 +1,21 @@
+package org.spongycastle.jce.interfaces;
+
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * allow us to set attributes on objects that can go into a PKCS12 store.
+ */
+public interface PKCS12BagAttributeCarrier
+{
+ void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute);
+
+ ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid);
+
+ Enumeration getBagAttributeKeys();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/netscape/NetscapeCertRequest.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/netscape/NetscapeCertRequest.java
new file mode 100644
index 000000000..145cfcb4f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/netscape/NetscapeCertRequest.java
@@ -0,0 +1,303 @@
+package org.spongycastle.jce.netscape;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ *
+ *
+ * Handles NetScape certificate request (KEYGEN), these are constructed as:
+ * <pre><code>
+ * SignedPublicKeyAndChallenge ::= SEQUENCE {
+ * publicKeyAndChallenge PublicKeyAndChallenge,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ *
+ * PublicKey's encoded-format has to be X.509.
+ *
+ **/
+public class NetscapeCertRequest
+ extends ASN1Object
+{
+ AlgorithmIdentifier sigAlg;
+ AlgorithmIdentifier keyAlg;
+ byte sigBits [];
+ String challenge;
+ DERBitString content;
+ PublicKey pubkey ;
+
+ private static ASN1Sequence getReq(
+ byte[] r)
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(r));
+
+ return ASN1Sequence.getInstance(aIn.readObject());
+ }
+
+ public NetscapeCertRequest(
+ byte[] req)
+ throws IOException
+ {
+ this(getReq(req));
+ }
+
+ public NetscapeCertRequest (ASN1Sequence spkac)
+ {
+ try
+ {
+
+ //
+ // SignedPublicKeyAndChallenge ::= SEQUENCE {
+ // publicKeyAndChallenge PublicKeyAndChallenge,
+ // signatureAlgorithm AlgorithmIdentifier,
+ // signature BIT STRING
+ // }
+ //
+ if (spkac.size() != 3)
+ {
+ throw new IllegalArgumentException("invalid SPKAC (size):"
+ + spkac.size());
+ }
+
+ sigAlg = new AlgorithmIdentifier((ASN1Sequence)spkac
+ .getObjectAt(1));
+ sigBits = ((DERBitString)spkac.getObjectAt(2)).getBytes();
+
+ //
+ // PublicKeyAndChallenge ::= SEQUENCE {
+ // spki SubjectPublicKeyInfo,
+ // challenge IA5STRING
+ // }
+ //
+ ASN1Sequence pkac = (ASN1Sequence)spkac.getObjectAt(0);
+
+ if (pkac.size() != 2)
+ {
+ throw new IllegalArgumentException("invalid PKAC (len): "
+ + pkac.size());
+ }
+
+ challenge = ((DERIA5String)pkac.getObjectAt(1)).getString();
+
+ //this could be dangerous, as ASN.1 decoding/encoding
+ //could potentially alter the bytes
+ content = new DERBitString(pkac);
+
+ SubjectPublicKeyInfo pubkeyinfo = new SubjectPublicKeyInfo(
+ (ASN1Sequence)pkac.getObjectAt(0));
+
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(
+ pubkeyinfo).getBytes());
+
+ keyAlg = pubkeyinfo.getAlgorithmId();
+ pubkey = KeyFactory.getInstance(keyAlg.getObjectId().getId(), "SC")
+ .generatePublic(xspec);
+
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException(e.toString());
+ }
+ }
+
+ public NetscapeCertRequest(
+ String challenge,
+ AlgorithmIdentifier signing_alg,
+ PublicKey pub_key) throws NoSuchAlgorithmException,
+ InvalidKeySpecException, NoSuchProviderException
+ {
+
+ this.challenge = challenge;
+ sigAlg = signing_alg;
+ pubkey = pub_key;
+
+ ASN1EncodableVector content_der = new ASN1EncodableVector();
+ content_der.add(getKeySpec());
+ //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
+ content_der.add(new DERIA5String(challenge));
+
+ try
+ {
+ content = new DERBitString(new DERSequence(content_der));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException("exception encoding key: " + e.toString());
+ }
+ }
+
+ public String getChallenge()
+ {
+ return challenge;
+ }
+
+ public void setChallenge(String value)
+ {
+ challenge = value;
+ }
+
+ public AlgorithmIdentifier getSigningAlgorithm()
+ {
+ return sigAlg;
+ }
+
+ public void setSigningAlgorithm(AlgorithmIdentifier value)
+ {
+ sigAlg = value;
+ }
+
+ public AlgorithmIdentifier getKeyAlgorithm()
+ {
+ return keyAlg;
+ }
+
+ public void setKeyAlgorithm(AlgorithmIdentifier value)
+ {
+ keyAlg = value;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ return pubkey;
+ }
+
+ public void setPublicKey(PublicKey value)
+ {
+ pubkey = value;
+ }
+
+ public boolean verify(String challenge) throws NoSuchAlgorithmException,
+ InvalidKeyException, SignatureException, NoSuchProviderException
+ {
+ if (!challenge.equals(this.challenge))
+ {
+ return false;
+ }
+
+ //
+ // Verify the signature .. shows the response was generated
+ // by someone who knew the associated private key
+ //
+ Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
+ "SC");
+ sig.initVerify(pubkey);
+ sig.update(content.getBytes());
+
+ return sig.verify(sigBits);
+ }
+
+ public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException,
+ InvalidKeyException, SignatureException, NoSuchProviderException,
+ InvalidKeySpecException
+ {
+ sign(priv_key, null);
+ }
+
+ public void sign(PrivateKey priv_key, SecureRandom rand)
+ throws NoSuchAlgorithmException, InvalidKeyException,
+ SignatureException, NoSuchProviderException,
+ InvalidKeySpecException
+ {
+ Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(),
+ "SC");
+
+ if (rand != null)
+ {
+ sig.initSign(priv_key, rand);
+ }
+ else
+ {
+ sig.initSign(priv_key);
+ }
+
+ ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+ pkac.add(getKeySpec());
+ pkac.add(new DERIA5String(challenge));
+
+ try
+ {
+ sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException ioe)
+ {
+ throw new SignatureException(ioe.getMessage());
+ }
+
+ sigBits = sig.sign();
+ }
+
+ private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException,
+ InvalidKeySpecException, NoSuchProviderException
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ ASN1Primitive obj = null;
+ try
+ {
+
+ baos.write(pubkey.getEncoded());
+ baos.close();
+
+ ASN1InputStream derin = new ASN1InputStream(
+ new ByteArrayInputStream(baos.toByteArray()));
+
+ obj = derin.readObject();
+ }
+ catch (IOException ioe)
+ {
+ throw new InvalidKeySpecException(ioe.getMessage());
+ }
+ return obj;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector spkac = new ASN1EncodableVector();
+ ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+ try
+ {
+ pkac.add(getKeySpec());
+ }
+ catch (Exception e)
+ {
+ //ignore
+ }
+
+ pkac.add(new DERIA5String(challenge));
+
+ spkac.add(new DERSequence(pkac));
+ spkac.add(sigAlg);
+ spkac.add(new DERBitString(sigBits));
+
+ return new DERSequence(spkac);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/AnnotatedException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/AnnotatedException.java
new file mode 100644
index 000000000..733a2a909
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/AnnotatedException.java
@@ -0,0 +1,32 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.jce.exception.ExtException;
+
+public class AnnotatedException
+ extends Exception
+ implements ExtException
+{
+ private Throwable _underlyingException;
+
+ AnnotatedException(String string, Throwable e)
+ {
+ super(string);
+
+ _underlyingException = e;
+ }
+
+ AnnotatedException(String string)
+ {
+ this(string, null);
+ }
+
+ Throwable getUnderlyingException()
+ {
+ return _underlyingException;
+ }
+
+ public Throwable getCause()
+ {
+ return _underlyingException;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BouncyCastleProvider.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BouncyCastleProvider.java
new file mode 100644
index 000000000..245e46cd5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BouncyCastleProvider.java
@@ -0,0 +1,283 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivateKey;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * To add the provider at runtime use:
+ * <pre>
+ * import java.security.Security;
+ * import org.spongycastle.jce.provider.BouncyCastleProvider;
+ *
+ * Security.addProvider(new BouncyCastleProvider());
+ * </pre>
+ * The provider can also be configured as part of your environment via
+ * static registration by adding an entry to the java.security properties
+ * file (found in $JAVA_HOME/jre/lib/security/java.security, where
+ * $JAVA_HOME is the location of your JDK/JRE distribution). You'll find
+ * detailed instructions in the file but basically it comes down to adding
+ * a line:
+ * <pre>
+ * <code>
+ * security.provider.&lt;n&gt;=org.spongycastle.jce.provider.BouncyCastleProvider
+ * </code>
+ * </pre>
+ * Where &lt;n&gt; is the preference you want the provider at (1 being the
+ * most preferred).
+ * <p>Note: JCE algorithm names should be upper-case only so the case insensitive
+ * test for getInstance works.
+ */
+public final class BouncyCastleProvider extends Provider
+ implements ConfigurableProvider
+{
+ private static String info = "BouncyCastle Security Provider v1.50";
+
+ public static final String PROVIDER_NAME = "SC";
+
+ public static final ProviderConfiguration CONFIGURATION = new BouncyCastleProviderConfiguration();
+
+ private static final Map keyInfoConverters = new HashMap();
+
+ /*
+ * Configurable symmetric ciphers
+ */
+ private static final String SYMMETRIC_PACKAGE = "org.spongycastle.jcajce.provider.symmetric.";
+
+ private static final String[] SYMMETRIC_GENERIC =
+ {
+ "PBEPBKDF2", "PBEPKCS12"
+ };
+
+ private static final String[] SYMMETRIC_MACS =
+ {
+ "SipHash"
+ };
+
+ private static final String[] SYMMETRIC_CIPHERS =
+ {
+ "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede",
+ "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5",
+ "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "TEA", "Twofish", "Threefish",
+ "VMPC", "VMPCKSA3", "XTEA", "XSalsa20"
+ };
+
+ /*
+ * Configurable asymmetric ciphers
+ */
+ private static final String ASYMMETRIC_PACKAGE = "org.spongycastle.jcajce.provider.asymmetric.";
+
+ // this one is required for GNU class path - it needs to be loaded first as the
+ // later ones configure it.
+ private static final String[] ASYMMETRIC_GENERIC =
+ {
+ "X509", "IES"
+ };
+
+ private static final String[] ASYMMETRIC_CIPHERS =
+ {
+ "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145"
+ };
+
+ /*
+ * Configurable digests
+ */
+ private static final String DIGEST_PACKAGE = "org.spongycastle.jcajce.provider.digest.";
+ private static final String[] DIGESTS =
+ {
+ "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool"
+ };
+
+ /*
+ * Configurable keystores
+ */
+ private static final String KEYSTORE_PACKAGE = "org.spongycastle.jcajce.provider.keystore.";
+ private static final String[] KEYSTORES =
+ {
+ "BC", "PKCS12"
+ };
+
+ /**
+ * Construct a new provider. This should only be required when
+ * using runtime registration of the provider using the
+ * <code>Security.addProvider()</code> mechanism.
+ */
+ public BouncyCastleProvider()
+ {
+ super(PROVIDER_NAME, 1.50, info);
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ setup();
+ return null;
+ }
+ });
+ }
+
+ private void setup()
+ {
+ loadAlgorithms(DIGEST_PACKAGE, DIGESTS);
+
+ loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_GENERIC);
+
+ loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_MACS);
+
+ loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_CIPHERS);
+
+ loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_GENERIC);
+
+ loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_CIPHERS);
+
+ loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES);
+
+ //
+ // X509Store
+ //
+ put("X509Store.CERTIFICATE/COLLECTION", "org.spongycastle.jce.provider.X509StoreCertCollection");
+ put("X509Store.ATTRIBUTECERTIFICATE/COLLECTION", "org.spongycastle.jce.provider.X509StoreAttrCertCollection");
+ put("X509Store.CRL/COLLECTION", "org.spongycastle.jce.provider.X509StoreCRLCollection");
+ put("X509Store.CERTIFICATEPAIR/COLLECTION", "org.spongycastle.jce.provider.X509StoreCertPairCollection");
+
+ put("X509Store.CERTIFICATE/LDAP", "org.spongycastle.jce.provider.X509StoreLDAPCerts");
+ put("X509Store.CRL/LDAP", "org.spongycastle.jce.provider.X509StoreLDAPCRLs");
+ put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "org.spongycastle.jce.provider.X509StoreLDAPAttrCerts");
+ put("X509Store.CERTIFICATEPAIR/LDAP", "org.spongycastle.jce.provider.X509StoreLDAPCertPairs");
+
+ //
+ // X509StreamParser
+ //
+ put("X509StreamParser.CERTIFICATE", "org.spongycastle.jce.provider.X509CertParser");
+ put("X509StreamParser.ATTRIBUTECERTIFICATE", "org.spongycastle.jce.provider.X509AttrCertParser");
+ put("X509StreamParser.CRL", "org.spongycastle.jce.provider.X509CRLParser");
+ put("X509StreamParser.CERTIFICATEPAIR", "org.spongycastle.jce.provider.X509CertPairParser");
+
+ //
+ // cipher engines
+ //
+ put("Cipher.BROKENPBEWITHMD5ANDDES", "org.spongycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES");
+
+ put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.spongycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
+
+
+ put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.spongycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
+
+ // Certification Path API
+ put("CertPathValidator.RFC3281", "org.spongycastle.jce.provider.PKIXAttrCertPathValidatorSpi");
+ put("CertPathBuilder.RFC3281", "org.spongycastle.jce.provider.PKIXAttrCertPathBuilderSpi");
+ put("CertPathValidator.RFC3280", "org.spongycastle.jce.provider.PKIXCertPathValidatorSpi");
+ put("CertPathBuilder.RFC3280", "org.spongycastle.jce.provider.PKIXCertPathBuilderSpi");
+ put("CertPathValidator.PKIX", "org.spongycastle.jce.provider.PKIXCertPathValidatorSpi");
+ put("CertPathBuilder.PKIX", "org.spongycastle.jce.provider.PKIXCertPathBuilderSpi");
+ put("CertStore.Collection", "org.spongycastle.jce.provider.CertStoreCollectionSpi");
+ put("CertStore.LDAP", "org.spongycastle.jce.provider.X509LDAPCertStoreSpi");
+ put("CertStore.Multi", "org.spongycastle.jce.provider.MultiCertStoreSpi");
+ put("Alg.Alias.CertStore.X509LDAP", "LDAP");
+ }
+
+ private void loadAlgorithms(String packageName, String[] names)
+ {
+ for (int i = 0; i != names.length; i++)
+ {
+ Class clazz = null;
+ try
+ {
+ ClassLoader loader = this.getClass().getClassLoader();
+
+ if (loader != null)
+ {
+ clazz = loader.loadClass(packageName + names[i] + "$Mappings");
+ }
+ else
+ {
+ clazz = Class.forName(packageName + names[i] + "$Mappings");
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ // ignore
+ }
+
+ if (clazz != null)
+ {
+ try
+ {
+ ((AlgorithmProvider)clazz.newInstance()).configure(this);
+ }
+ catch (Exception e)
+ { // this should never ever happen!!
+ throw new InternalError("cannot create instance of "
+ + packageName + names[i] + "$Mappings : " + e);
+ }
+ }
+ }
+ }
+
+ public void setParameter(String parameterName, Object parameter)
+ {
+ synchronized (CONFIGURATION)
+ {
+ ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
+ }
+ }
+
+ public boolean hasAlgorithm(String type, String name)
+ {
+ return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
+ }
+
+ public void addAlgorithm(String key, String value)
+ {
+ if (containsKey(key))
+ {
+ throw new IllegalStateException("duplicate provider key (" + key + ") found");
+ }
+
+ put(key, value);
+ }
+
+ public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
+ {
+ keyInfoConverters.put(oid, keyInfoConverter);
+ }
+
+ public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePublic(publicKeyInfo);
+ }
+
+ public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePrivate(privateKeyInfo);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java
new file mode 100644
index 000000000..9421c517a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java
@@ -0,0 +1,167 @@
+package org.spongycastle.jce.provider;
+
+import java.security.Permission;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.config.ProviderConfigurationPermission;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+class BouncyCastleProviderConfiguration
+ implements ProviderConfiguration
+{
+ private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+ private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.EC_IMPLICITLY_CA);
+ private static Permission BC_DH_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS);
+ private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS);
+
+ private ThreadLocal ecThreadSpec = new ThreadLocal();
+ private ThreadLocal dhThreadSpec = new ThreadLocal();
+
+ private volatile ECParameterSpec ecImplicitCaParams;
+ private volatile Object dhDefaultParams;
+
+ void setParameter(String parameterName, Object parameter)
+ {
+ SecurityManager securityManager = System.getSecurityManager();
+
+ if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+ {
+ ECParameterSpec curveSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
+ }
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ curveSpec = (ECParameterSpec)parameter;
+ }
+ else // assume java.security.spec
+ {
+ curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+ }
+
+ if (curveSpec == null)
+ {
+ ecThreadSpec.remove();
+ }
+ else
+ {
+ ecThreadSpec.set(curveSpec);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_PERMISSION);
+ }
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ ecImplicitCaParams = (ECParameterSpec)parameter;
+ }
+ else // assume java.security.spec
+ {
+ ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS))
+ {
+ Object dhSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_DH_LOCAL_PERMISSION);
+ }
+
+ if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+ {
+ dhSpec = parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec");
+ }
+
+ if (dhSpec == null)
+ {
+ dhThreadSpec.remove();
+ }
+ else
+ {
+ dhThreadSpec.set(dhSpec);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.DH_DEFAULT_PARAMS))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_DH_PERMISSION);
+ }
+
+ if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+ {
+ dhDefaultParams = parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]");
+ }
+ }
+ }
+
+ public ECParameterSpec getEcImplicitlyCa()
+ {
+ ECParameterSpec spec = (ECParameterSpec)ecThreadSpec.get();
+
+ if (spec != null)
+ {
+ return spec;
+ }
+
+ return ecImplicitCaParams;
+ }
+
+ public DHParameterSpec getDHDefaultParameters(int keySize)
+ {
+ Object params = dhThreadSpec.get();
+ if (params == null)
+ {
+ params = dhDefaultParams;
+ }
+
+ if (params instanceof DHParameterSpec)
+ {
+ DHParameterSpec spec = (DHParameterSpec)params;
+
+ if (spec.getP().bitLength() == keySize)
+ {
+ return spec;
+ }
+ }
+ else if (params instanceof DHParameterSpec[])
+ {
+ DHParameterSpec[] specs = (DHParameterSpec[])params;
+
+ for (int i = 0; i != specs.length; i++)
+ {
+ if (specs[i].getP().bitLength() == keySize)
+ {
+ return specs[i];
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenJCEBlockCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenJCEBlockCipher.java
new file mode 100644
index 000000000..95304581f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenJCEBlockCipher.java
@@ -0,0 +1,621 @@
+package org.spongycastle.jce.provider;
+
+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.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DataLengthException;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.engines.DESEngine;
+import org.spongycastle.crypto.engines.DESedeEngine;
+import org.spongycastle.crypto.engines.TwofishEngine;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.CFBBlockCipher;
+import org.spongycastle.crypto.modes.CTSBlockCipher;
+import org.spongycastle.crypto.modes.OFBBlockCipher;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.crypto.params.RC2Parameters;
+import org.spongycastle.crypto.params.RC5Parameters;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.util.Strings;
+
+public class BrokenJCEBlockCipher
+ implements BrokenPBE
+{
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ RC2ParameterSpec.class,
+ RC5ParameterSpec.class
+ };
+
+ private BufferedBlockCipher cipher;
+ private ParametersWithIV ivParam;
+
+ private int pbeType = PKCS12;
+ private int pbeHash = SHA1;
+ private int pbeKeySize;
+ private int pbeIvSize;
+
+ private int ivLength = 0;
+
+ private AlgorithmParameters engineParams = null;
+
+ protected BrokenJCEBlockCipher(
+ BlockCipher engine)
+ {
+ cipher = new PaddedBufferedBlockCipher(engine);
+ }
+
+ protected BrokenJCEBlockCipher(
+ BlockCipher engine,
+ int pbeType,
+ int pbeHash,
+ int pbeKeySize,
+ int pbeIvSize)
+ {
+ cipher = new PaddedBufferedBlockCipher(engine);
+
+ this.pbeType = pbeType;
+ this.pbeHash = pbeHash;
+ this.pbeKeySize = pbeKeySize;
+ this.pbeIvSize = pbeIvSize;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return (ivParam != null) ? ivParam.getIV() : null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return cipher.getOutputSize(inputLen);
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (ivParam != null)
+ {
+ String name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+ if (name.indexOf('/') >= 0)
+ {
+ name = name.substring(0, name.indexOf('/'));
+ }
+
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(ivParam.getIV());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ {
+ String modeName = Strings.toUpperCase(mode);
+
+ if (modeName.equals("ECB"))
+ {
+ ivLength = 0;
+ cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else if (modeName.equals("CBC"))
+ {
+ ivLength = cipher.getUnderlyingCipher().getBlockSize();
+ cipher = new PaddedBufferedBlockCipher(
+ new CBCBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ else if (modeName.startsWith("OFB"))
+ {
+ ivLength = cipher.getUnderlyingCipher().getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new PaddedBufferedBlockCipher(
+ new OFBBlockCipher(cipher.getUnderlyingCipher(), wordSize));
+ }
+ else
+ {
+ cipher = new PaddedBufferedBlockCipher(
+ new OFBBlockCipher(cipher.getUnderlyingCipher(), 8 * cipher.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("CFB"))
+ {
+ ivLength = cipher.getUnderlyingCipher().getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new PaddedBufferedBlockCipher(
+ new CFBBlockCipher(cipher.getUnderlyingCipher(), wordSize));
+ }
+ else
+ {
+ cipher = new PaddedBufferedBlockCipher(
+ new CFBBlockCipher(cipher.getUnderlyingCipher(), 8 * cipher.getBlockSize()));
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("can't support mode " + mode);
+ }
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String paddingName = Strings.toUpperCase(padding);
+
+ if (paddingName.equals("NOPADDING"))
+ {
+ cipher = new BufferedBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING") || paddingName.equals("ISO10126PADDING"))
+ {
+ cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else if (paddingName.equals("WITHCTS"))
+ {
+ cipher = new CTSBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ //
+ // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+ //
+ if (key instanceof BCPBEKey)
+ {
+ param = BrokenPBE.Util.makePBEParameters((BCPBEKey)key, params, pbeType, pbeHash,
+ cipher.getUnderlyingCipher().getAlgorithmName(), pbeKeySize, pbeIvSize);
+
+ if (pbeIvSize != 0)
+ {
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ if (ivLength != 0)
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ }
+ else if (params instanceof RC2ParameterSpec)
+ {
+ RC2ParameterSpec rc2Param = (RC2ParameterSpec)params;
+
+ param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+
+ if (rc2Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, rc2Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params instanceof RC5ParameterSpec)
+ {
+ RC5ParameterSpec rc5Param = (RC5ParameterSpec)params;
+
+ param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+ if (rc5Param.getWordSize() != 32)
+ {
+ throw new IllegalArgumentException("can only accept RC5 word size 32 (at the moment...)");
+ }
+ if ((rc5Param.getIV() != null) && (ivLength != 0))
+ {
+ param = new ParametersWithIV(param, rc5Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ }
+
+ if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+ {
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+
+ if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+ {
+ byte[] iv = new byte[ivLength];
+
+ random.nextBytes(iv);
+ param = new ParametersWithIV(param, iv);
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("no IV set when one expected");
+ }
+ }
+
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ System.out.println("eeek!");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ for (int i = 0; i != availableSpecs.length; i++)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(availableSpecs[i]);
+ break;
+ }
+ catch (Exception e)
+ {
+ continue;
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineParams = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ int length = cipher.getUpdateOutputSize(inputLen);
+
+ if (length > 0)
+ {
+ byte[] out = new byte[length];
+
+ cipher.processBytes(input, inputOffset, inputLen, out, 0);
+ return out;
+ }
+
+ cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ int len = 0;
+ byte[] tmp = new byte[engineGetOutputSize(inputLen)];
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+ }
+
+ try
+ {
+ len += cipher.doFinal(tmp, len);
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ byte[] out = new byte[len];
+
+ System.arraycopy(tmp, 0, out, 0, len);
+
+ return out;
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ int len = 0;
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ try
+ {
+ return len + cipher.doFinal(output, outputOffset + len);
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineWrap(
+ Key key)
+ throws IllegalBlockSizeException, java.security.InvalidKeyException
+ {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null)
+ {
+ throw new InvalidKeyException("Cannot wrap key, null encoding.");
+ }
+
+ try
+ {
+ return engineDoFinal(encoded, 0, encoded.length);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ }
+
+ protected Key engineUnwrap(
+ byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException
+ {
+ byte[] encoded = null;
+ try
+ {
+ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ catch (IllegalBlockSizeException e2)
+ {
+ throw new InvalidKeyException(e2.getMessage());
+ }
+
+ if (wrappedKeyType == Cipher.SECRET_KEY)
+ {
+ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+ }
+ else
+ {
+ try
+ {
+ KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+ if (wrappedKeyType == Cipher.PUBLIC_KEY)
+ {
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ }
+ else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (InvalidKeySpecException e2)
+ {
+ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+ }
+
+ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+ }
+ }
+
+ /*
+ * The ciphers that inherit from us.
+ */
+
+ /**
+ * PBEWithMD5AndDES
+ */
+ static public class BrokePBEWithMD5AndDES
+ extends BrokenJCEBlockCipher
+ {
+ public BrokePBEWithMD5AndDES()
+ {
+ super(new CBCBlockCipher(new DESEngine()), PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndDES
+ */
+ static public class BrokePBEWithSHA1AndDES
+ extends BrokenJCEBlockCipher
+ {
+ public BrokePBEWithSHA1AndDES()
+ {
+ super(new CBCBlockCipher(new DESEngine()), PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd3-KeyTripleDES-CBC
+ */
+ static public class BrokePBEWithSHAAndDES3Key
+ extends BrokenJCEBlockCipher
+ {
+ public BrokePBEWithSHAAndDES3Key()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1, 192, 64);
+ }
+ }
+
+ /**
+ * OldPBEWithSHAAnd3-KeyTripleDES-CBC
+ */
+ static public class OldPBEWithSHAAndDES3Key
+ extends BrokenJCEBlockCipher
+ {
+ public OldPBEWithSHAAndDES3Key()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()), OLD_PKCS12, SHA1, 192, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd2-KeyTripleDES-CBC
+ */
+ static public class BrokePBEWithSHAAndDES2Key
+ extends BrokenJCEBlockCipher
+ {
+ public BrokePBEWithSHAAndDES2Key()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ /**
+ * OldPBEWithSHAAndTwofish-CBC
+ */
+ static public class OldPBEWithSHAAndTwofish
+ extends BrokenJCEBlockCipher
+ {
+ public OldPBEWithSHAAndTwofish()
+ {
+ super(new CBCBlockCipher(new TwofishEngine()), OLD_PKCS12, SHA1, 256, 128);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenKDF2BytesGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenKDF2BytesGenerator.java
new file mode 100644
index 000000000..0e7343e7f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenKDF2BytesGenerator.java
@@ -0,0 +1,127 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.crypto.DataLengthException;
+import org.spongycastle.crypto.DerivationFunction;
+import org.spongycastle.crypto.DerivationParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.params.KDFParameters;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by IEEE P1363a
+ * <br>
+ * This implementation is based on draft 9 of IEEE P1363a. <b>Note:</b>
+ * as this is still a draft the output of this generator may change, don't
+ * use it for anything that might be subject to long term storage.
+ */
+public class BrokenKDF2BytesGenerator
+ implements DerivationFunction
+{
+ private Digest digest;
+ private byte[] shared;
+ private byte[] iv;
+
+ /**
+ * Construct a KDF2 Parameters generator. Generates key material
+ * according to IEEE P1363a - if you want orthodox results you should
+ * use a digest specified in the standard.
+ * <p>
+ * <b>Note:</b> IEEE P1363a standard is still a draft standard, if the standard
+ * changes this function, the output of this function will change as well.
+ * Don't use this routine for anything subject to long term storage.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public BrokenKDF2BytesGenerator(
+ Digest digest)
+ {
+ this.digest = digest;
+ }
+
+ public void init(
+ DerivationParameters param)
+ {
+ if (!(param instanceof KDFParameters))
+ {
+ throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
+ }
+
+ KDFParameters p = (KDFParameters)param;
+
+ shared = p.getSharedSecret();
+ iv = p.getIV();
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public Digest getDigest()
+ {
+ return digest;
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes generated from
+ * the derivation function.
+ *
+ * @throws IllegalArgumentException if the size of the request will cause an overflow.
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public int generateBytes(
+ byte[] out,
+ int outOff,
+ int len)
+ throws DataLengthException, IllegalArgumentException
+ {
+ if ((out.length - len) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ long oBits = len * 8;
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^23 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBits > (digest.getDigestSize() * 8 * (2L^32 - 1)))
+ {
+ new IllegalArgumentException("Output length to large");
+ }
+
+ int cThreshold = (int)(oBits / digest.getDigestSize());
+
+ byte[] dig = null;
+
+ dig = new byte[digest.getDigestSize()];
+
+ for (int counter = 1; counter <= cThreshold; counter++)
+ {
+ digest.update(shared, 0, shared.length);
+
+ digest.update((byte)(counter & 0xff));
+ digest.update((byte)((counter >> 8) & 0xff));
+ digest.update((byte)((counter >> 16) & 0xff));
+ digest.update((byte)((counter >> 24) & 0xff));
+
+ digest.update(iv, 0, iv.length);
+
+ digest.doFinal(dig, 0);
+
+ if ((len - outOff) > dig.length)
+ {
+ System.arraycopy(dig, 0, out, outOff, dig.length);
+ outOff += dig.length;
+ }
+ else
+ {
+ System.arraycopy(dig, 0, out, outOff, len - outOff);
+ }
+ }
+
+ digest.reset();
+
+ return len;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenPBE.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenPBE.java
new file mode 100644
index 000000000..6fb4a7ecd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/BrokenPBE.java
@@ -0,0 +1,441 @@
+package org.spongycastle.jce.provider;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS5S1ParametersGenerator;
+import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0,
+ * with a bug affecting 180 bit plus keys - this class is only here to
+ * allow smooth migration of the version 0 keystore to version 1. Don't
+ * use it (it won't be staying around).
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
+ * RSA's PKCS12 Page</a>
+ */
+class OldPKCS12ParametersGenerator
+ extends PBEParametersGenerator
+{
+ public static final int KEY_MATERIAL = 1;
+ public static final int IV_MATERIAL = 2;
+ public static final int MAC_MATERIAL = 3;
+
+ private Digest digest;
+
+ private int u;
+ private int v;
+
+ /**
+ * Construct a PKCS 12 Parameters generator. This constructor will
+ * accept MD5, SHA1, and RIPEMD160.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ * @exception IllegalArgumentException if an unknown digest is passed in.
+ */
+ public OldPKCS12ParametersGenerator(
+ Digest digest)
+ {
+ this.digest = digest;
+ if (digest instanceof MD5Digest)
+ {
+ u = 128 / 8;
+ v = 512 / 8;
+ }
+ else if (digest instanceof SHA1Digest)
+ {
+ u = 160 / 8;
+ v = 512 / 8;
+ }
+ else if (digest instanceof RIPEMD160Digest)
+ {
+ u = 160 / 8;
+ v = 512 / 8;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
+ }
+ }
+
+ /**
+ * add a + b + 1, returning the result in a. The a value is treated
+ * as a BigInteger of length (b.length * 8) bits. The result is
+ * modulo 2^b.length in case of overflow.
+ */
+ private void adjust(
+ byte[] a,
+ int aOff,
+ byte[] b)
+ {
+ int x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
+
+ a[aOff + b.length - 1] = (byte)x;
+ x >>>= 8;
+
+ for (int i = b.length - 2; i >= 0; i--)
+ {
+ x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+ a[aOff + i] = (byte)x;
+ x >>>= 8;
+ }
+ }
+
+ /**
+ * generation of a derived key ala PKCS12 V1.0.
+ */
+ private byte[] generateDerivedKey(
+ int idByte,
+ int n)
+ {
+ byte[] D = new byte[v];
+ byte[] dKey = new byte[n];
+
+ for (int i = 0; i != D.length; i++)
+ {
+ D[i] = (byte)idByte;
+ }
+
+ byte[] S;
+
+ if ((salt != null) && (salt.length != 0))
+ {
+ S = new byte[v * ((salt.length + v - 1) / v)];
+
+ for (int i = 0; i != S.length; i++)
+ {
+ S[i] = salt[i % salt.length];
+ }
+ }
+ else
+ {
+ S = new byte[0];
+ }
+
+ byte[] P;
+
+ if ((password != null) && (password.length != 0))
+ {
+ P = new byte[v * ((password.length + v - 1) / v)];
+
+ for (int i = 0; i != P.length; i++)
+ {
+ P[i] = password[i % password.length];
+ }
+ }
+ else
+ {
+ P = new byte[0];
+ }
+
+ byte[] I = new byte[S.length + P.length];
+
+ System.arraycopy(S, 0, I, 0, S.length);
+ System.arraycopy(P, 0, I, S.length, P.length);
+
+ byte[] B = new byte[v];
+ int c = (n + u - 1) / u;
+
+ for (int i = 1; i <= c; i++)
+ {
+ byte[] A = new byte[u];
+
+ digest.update(D, 0, D.length);
+ digest.update(I, 0, I.length);
+ digest.doFinal(A, 0);
+ for (int j = 1; j != iterationCount; j++)
+ {
+ digest.update(A, 0, A.length);
+ digest.doFinal(A, 0);
+ }
+
+ for (int j = 0; j != B.length; j++)
+ {
+ B[i] = A[j % A.length];
+ }
+
+ for (int j = 0; j != I.length / v; j++)
+ {
+ adjust(I, j * v, B);
+ }
+
+ if (i == c)
+ {
+ System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
+ }
+ else
+ {
+ System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
+ }
+ }
+
+ return dKey;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+ byte[] iv = generateDerivedKey(IV_MATERIAL, ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(MAC_MATERIAL, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+}
+
+public interface BrokenPBE
+{
+ //
+ // PBE Based encryption constants - by default we do PKCS12 with SHA-1
+ //
+ static final int MD5 = 0;
+ static final int SHA1 = 1;
+ static final int RIPEMD160 = 2;
+
+ static final int PKCS5S1 = 0;
+ static final int PKCS5S2 = 1;
+ static final int PKCS12 = 2;
+ static final int OLD_PKCS12 = 3;
+
+ /**
+ * uses the appropriate mixer to generate the key and IV if neccessary.
+ */
+ static class Util
+ {
+ /**
+ * a faulty parity routine...
+ *
+ * @param bytes the byte array to set the parity on.
+ */
+ static private void setOddParity(
+ byte[] bytes)
+ {
+ for (int i = 0; i < bytes.length; i++)
+ {
+ int b = bytes[i];
+ bytes[i] = (byte)((b & 0xfe) |
+ (((b >> 1) ^
+ (b >> 2) ^
+ (b >> 3) ^
+ (b >> 4) ^
+ (b >> 5) ^
+ (b >> 6) ^
+ (b >> 7)) ^ 0x01));
+ }
+ }
+
+ static private PBEParametersGenerator makePBEGenerator(
+ int type,
+ int hash)
+ {
+ PBEParametersGenerator generator;
+
+ if (type == PKCS5S1)
+ {
+ switch (hash)
+ {
+ case MD5:
+ generator = new PKCS5S1ParametersGenerator(new MD5Digest());
+ break;
+ case SHA1:
+ generator = new PKCS5S1ParametersGenerator(new SHA1Digest());
+ break;
+ default:
+ throw new IllegalStateException("PKCS5 scheme 1 only supports only MD5 and SHA1.");
+ }
+ }
+ else if (type == PKCS5S2)
+ {
+ generator = new PKCS5S2ParametersGenerator();
+ }
+ else if (type == OLD_PKCS12)
+ {
+ switch (hash)
+ {
+ case MD5:
+ generator = new OldPKCS12ParametersGenerator(new MD5Digest());
+ break;
+ case SHA1:
+ generator = new OldPKCS12ParametersGenerator(new SHA1Digest());
+ break;
+ case RIPEMD160:
+ generator = new OldPKCS12ParametersGenerator(new RIPEMD160Digest());
+ break;
+ default:
+ throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+ }
+ }
+ else
+ {
+ switch (hash)
+ {
+ case MD5:
+ generator = new PKCS12ParametersGenerator(new MD5Digest());
+ break;
+ case SHA1:
+ generator = new PKCS12ParametersGenerator(new SHA1Digest());
+ break;
+ case RIPEMD160:
+ generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
+ break;
+ default:
+ throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+ }
+ }
+
+ return generator;
+ }
+
+ /**
+ * construct a key and iv (if neccessary) suitable for use with a
+ * Cipher.
+ */
+ static CipherParameters makePBEParameters(
+ BCPBEKey pbeKey,
+ AlgorithmParameterSpec spec,
+ int type,
+ int hash,
+ String targetAlgorithm,
+ int keySize,
+ int ivSize)
+ {
+ if ((spec == null) || !(spec instanceof PBEParameterSpec))
+ {
+ throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+ }
+
+ PBEParameterSpec pbeParam = (PBEParameterSpec)spec;
+ PBEParametersGenerator generator = makePBEGenerator(type, hash);
+ byte[] key = pbeKey.getEncoded();
+ CipherParameters param;
+
+ generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+ if (ivSize != 0)
+ {
+ param = generator.generateDerivedParameters(keySize, ivSize);
+ }
+ else
+ {
+ param = generator.generateDerivedParameters(keySize);
+ }
+
+ if (targetAlgorithm.startsWith("DES"))
+ {
+ if (param instanceof ParametersWithIV)
+ {
+ KeyParameter kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+
+ setOddParity(kParam.getKey());
+ }
+ else
+ {
+ KeyParameter kParam = (KeyParameter)param;
+
+ setOddParity(kParam.getKey());
+ }
+ }
+
+ for (int i = 0; i != key.length; i++)
+ {
+ key[i] = 0;
+ }
+
+ return param;
+ }
+
+ /**
+ * generate a PBE based key suitable for a MAC algorithm, the
+ * key size is chosen according the MAC size, or the hashing algorithm,
+ * whichever is greater.
+ */
+ static CipherParameters makePBEMacParameters(
+ BCPBEKey pbeKey,
+ AlgorithmParameterSpec spec,
+ int type,
+ int hash,
+ int keySize)
+ {
+ if ((spec == null) || !(spec instanceof PBEParameterSpec))
+ {
+ throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+ }
+
+ PBEParameterSpec pbeParam = (PBEParameterSpec)spec;
+ PBEParametersGenerator generator = makePBEGenerator(type, hash);
+ byte[] key = pbeKey.getEncoded();
+ CipherParameters param;
+
+ generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+ param = generator.generateDerivedMacParameters(keySize);
+
+ for (int i = 0; i != key.length; i++)
+ {
+ key[i] = 0;
+ }
+
+ return param;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertPathValidatorUtilities.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
new file mode 100644
index 000000000..7f13a2e98
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
@@ -0,0 +1,1426 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PolicyQualifierInfo;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+import org.spongycastle.x509.X509Store;
+
+public class CertPathValidatorUtilities
+{
+ protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ protected static final String CERTIFICATE_POLICIES = Extension.certificatePolicies.getId();
+ protected static final String BASIC_CONSTRAINTS = Extension.basicConstraints.getId();
+ protected static final String POLICY_MAPPINGS = Extension.policyMappings.getId();
+ protected static final String SUBJECT_ALTERNATIVE_NAME = Extension.subjectAlternativeName.getId();
+ protected static final String NAME_CONSTRAINTS = Extension.nameConstraints.getId();
+ protected static final String KEY_USAGE = Extension.keyUsage.getId();
+ protected static final String INHIBIT_ANY_POLICY = Extension.inhibitAnyPolicy.getId();
+ protected static final String ISSUING_DISTRIBUTION_POINT = Extension.issuingDistributionPoint.getId();
+ protected static final String DELTA_CRL_INDICATOR = Extension.deltaCRLIndicator.getId();
+ protected static final String POLICY_CONSTRAINTS = Extension.policyConstraints.getId();
+ protected static final String FRESHEST_CRL = Extension.freshestCRL.getId();
+ protected static final String CRL_DISTRIBUTION_POINTS = Extension.cRLDistributionPoints.getId();
+ protected static final String AUTHORITY_KEY_IDENTIFIER = Extension.authorityKeyIdentifier.getId();
+
+ protected static final String ANY_POLICY = "2.5.29.32.0";
+
+ protected static final String CRL_NUMBER = Extension.cRLNumber.getId();
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+ protected static final int CRL_SIGN = 6;
+
+ protected static final String[] crlReasons = new String[]{
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the default provider
+ * for signature verification.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors)
+ throws AnnotatedException
+ {
+ return findTrustAnchor(cert, trustAnchors, null);
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the specified
+ * provider for signature verification, or the default provider
+ * if null.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @param sigProvider the provider to use for signature verification
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors,
+ String sigProvider)
+ throws AnnotatedException
+ {
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+ X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
+
+ try
+ {
+ certSelectX509.setSubject(certIssuer.getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
+ }
+
+ Iterator iter = trustAnchors.iterator();
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X500Principal caName = new X500Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ verifyX509Certificate(cert, trustPublicKey, sigProvider);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ trustPublicKey = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ protected static void addAdditionalStoresFromAltNames(
+ X509Certificate cert,
+ ExtendedPKIXParameters pkixParams)
+ throws CertificateParsingException
+ {
+ // if in the IssuerAltName extension an URI
+ // is given, add an additinal X.509 store
+ if (cert.getIssuerAlternativeNames() != null)
+ {
+ Iterator it = cert.getIssuerAlternativeNames().iterator();
+ while (it.hasNext())
+ {
+ // look for URI
+ List list = (List)it.next();
+ if (list.get(0).equals(Integers.valueOf(GeneralName.uniformResourceIdentifier)))
+ {
+ // found
+ String temp = (String)list.get(1);
+ CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the issuer of an attribute certificate or certificate.
+ *
+ * @param cert The attribute certificate or certificate.
+ * @return The issuer as <code>X500Principal</code>.
+ */
+ protected static X500Principal getEncodedIssuerPrincipal(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getIssuerX500Principal();
+ }
+ else
+ {
+ return (X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0];
+ }
+ }
+
+ protected static Date getValidDate(PKIXParameters paramsPKIX)
+ {
+ Date validDate = paramsPKIX.getDate();
+
+ if (validDate == null)
+ {
+ validDate = new Date();
+ }
+
+ return validDate;
+ }
+
+ protected static X500Principal getSubjectPrincipal(X509Certificate cert)
+ {
+ return cert.getSubjectX500Principal();
+ }
+
+ protected static boolean isSelfIssued(X509Certificate cert)
+ {
+ return cert.getSubjectDN().equals(cert.getIssuerDN());
+ }
+
+
+ /**
+ * Extract the value of the given extension, if it exists.
+ *
+ * @param ext The extension object.
+ * @param oid The object identifier to obtain.
+ * @throws AnnotatedException if the extension cannot be read.
+ */
+ protected static ASN1Primitive getExtensionValue(
+ java.security.cert.X509Extension ext,
+ String oid)
+ throws AnnotatedException
+ {
+ byte[] bytes = ext.getExtensionValue(oid);
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ return getObject(oid, bytes);
+ }
+
+ private static ASN1Primitive getObject(
+ String oid,
+ byte[] ext)
+ throws AnnotatedException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(ext);
+ ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
+
+ aIn = new ASN1InputStream(octs.getOctets());
+ return aIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("exception processing extension " + oid, e);
+ }
+ }
+
+ protected static X500Principal getIssuerPrincipal(X509CRL crl)
+ {
+ return crl.getIssuerX500Principal();
+ }
+
+ protected static AlgorithmIdentifier getAlgorithmIdentifier(
+ PublicKey key)
+ throws CertPathValidatorException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ return info.getAlgorithmId();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
+ }
+ }
+
+ // crl checking
+
+
+ //
+ // policy checking
+ //
+
+ protected static final Set getQualifierSet(ASN1Sequence qualifiers)
+ throws CertPathValidatorException
+ {
+ Set pq = new HashSet();
+
+ if (qualifiers == null)
+ {
+ return pq;
+ }
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ Enumeration e = qualifiers.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
+ }
+ catch (IOException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+ }
+
+ bOut.reset();
+ }
+
+ return pq;
+ }
+
+ protected static PKIXPolicyNode removePolicyNode(
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
+
+ if (validPolicyTree == null)
+ {
+ return null;
+ }
+
+ if (_parent == null)
+ {
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ return null;
+ }
+ else
+ {
+ _parent.removeChild(_node);
+ removePolicyNodeRecurse(policyNodes, _node);
+
+ return validPolicyTree;
+ }
+ }
+
+ private static void removePolicyNodeRecurse(
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ policyNodes[_node.getDepth()].remove(_node);
+
+ if (_node.hasChildren())
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
+ removePolicyNodeRecurse(policyNodes, _child);
+ }
+ }
+ }
+
+
+ protected static boolean processCertD1i(
+ int index,
+ List[] policyNodes,
+ DERObjectIdentifier pOid,
+ Set pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
+ Set expectedPolicies = node.getExpectedPolicies();
+
+ if (expectedPolicies.contains(pOid.getId()))
+ {
+ Set childExpectedPolicies = new HashSet();
+ childExpectedPolicies.add(pOid.getId());
+
+ PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ childExpectedPolicies,
+ node,
+ pq,
+ pOid.getId(),
+ false);
+ node.addChild(child);
+ policyNodes[index].add(child);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected static void processCertD1ii(
+ int index,
+ List[] policyNodes,
+ DERObjectIdentifier _poid,
+ Set _pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Set _childExpectedPolicies = new HashSet();
+ _childExpectedPolicies.add(_poid.getId());
+
+ PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ _childExpectedPolicies,
+ _node,
+ _pq,
+ _poid.getId(),
+ false);
+ _node.addChild(_child);
+ policyNodes[index].add(_child);
+ return;
+ }
+ }
+ }
+
+ protected static void prepareNextCertB1(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ Map m_idp,
+ X509Certificate cert
+ )
+ throws AnnotatedException, CertPathValidatorException
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Certificate policies cannot be decoded.", e);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new AnnotatedException("Policy information cannot be decoded.", ex);
+ }
+ if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be built.", ex);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(
+ new ArrayList(), i,
+ (Set)m_idp.get(id_p),
+ p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode prepareNextCertB2(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ PKIXPolicyNode validPolicyTree)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return validPolicyTree;
+ }
+
+ protected static boolean isAnyPolicy(
+ Set policySet)
+ {
+ return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
+ }
+
+ protected static void addAdditionalStoreFromLocation(String location,
+ ExtendedPKIXParameters pkixParams)
+ {
+ if (pkixParams.isAdditionalLocationsEnabled())
+ {
+ try
+ {
+ if (location.startsWith("ldap://"))
+ {
+ // ldap://directory.d-trust.net/CN=D-TRUST
+ // Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE
+ // skip "ldap://"
+ location = location.substring(7);
+ // after first / baseDN starts
+ String base = null;
+ String url = null;
+ if (location.indexOf("/") != -1)
+ {
+ base = location.substring(location.indexOf("/"));
+ // URL
+ url = "ldap://"
+ + location.substring(0, location.indexOf("/"));
+ }
+ else
+ {
+ url = "ldap://" + location;
+ }
+ // use all purpose parameters
+ X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder(
+ url, base).build();
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CRL/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "ATTRIBUTECERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CERTIFICATEPAIR/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ }
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException("Exception adding X.509 stores.");
+ }
+ }
+ }
+
+ /**
+ * Return a Collection of all certificates or attribute certificates found
+ * in the X509Store's that are matching the certSelect criteriums.
+ *
+ * @param certSelect a {@link Selector} object that will be used to select
+ * the certificates
+ * @param certStores a List containing only {@link X509Store} objects. These
+ * are used to search for certificates.
+ * @return a Collection of all found {@link X509Certificate} or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} objects.
+ * May be empty but never <code>null</code>.
+ */
+ protected static Collection findCertificates(X509CertStoreSelector certSelect,
+ List certStores)
+ throws AnnotatedException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store certStore = (X509Store)obj;
+ try
+ {
+ certs.addAll(certStore.getMatches(certSelect));
+ }
+ catch (StoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+ else
+ {
+ CertStore certStore = (CertStore)obj;
+
+ try
+ {
+ certs.addAll(certStore.getCertificates(certSelect));
+ }
+ catch (CertStoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from certificate store.",
+ e);
+ }
+ }
+ }
+ return certs;
+ }
+
+ protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
+ List certStores)
+ throws AnnotatedException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store certStore = (X509Store)obj;
+ try
+ {
+ certs.addAll(certStore.getMatches(certSelect));
+ }
+ catch (StoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+ }
+ return certs;
+ }
+
+ protected static void addAdditionalStoresFromCRLDistributionPoint(
+ CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Distribution points could not be read.", e);
+ }
+ for (int i = 0; i < dps.length; i++)
+ {
+ DistributionPointName dpn = dps[i].getDistributionPoint();
+ // look for URIs in fullName
+ if (dpn != null)
+ {
+ if (dpn.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] genNames = GeneralNames.getInstance(
+ dpn.getName()).getNames();
+ // look for an URI
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
+ {
+ String location = DERIA5String.getInstance(
+ genNames[j].getName()).getString();
+ CertPathValidatorUtilities
+ .addAdditionalStoreFromLocation(location,
+ pkixParams);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add the CRL issuers from the cRLIssuer field of the distribution point or
+ * from the certificate if not given to the issuer criterion of the
+ * <code>selector</code>.
+ * <p/>
+ * The <code>issuerPrincipals</code> are a collection with a single
+ * <code>X500Principal</code> for <code>X509Certificate</code>s. For
+ * {@link X509AttributeCertificate}s the issuer may contain more than one
+ * <code>X500Principal</code>.
+ *
+ * @param dp The distribution point.
+ * @param issuerPrincipals The issuers of the certificate or attribute
+ * certificate which contains the distribution point.
+ * @param selector The CRL selector.
+ * @param pkixParams The PKIX parameters containing the cert stores.
+ * @throws AnnotatedException if an exception occurs while processing.
+ * @throws ClassCastException if <code>issuerPrincipals</code> does not
+ * contain only <code>X500Principal</code>s.
+ */
+ protected static void getCRLIssuersFromDistributionPoint(
+ DistributionPoint dp,
+ Collection issuerPrincipals,
+ X509CRLSelector selector,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ List issuers = new ArrayList();
+ // indirect CRL
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ // look for a DN
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ issuers.add(new X500Principal(genNames[j].getName()
+ .toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.",
+ e);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * certificate issuer is CRL issuer, distributionPoint field MUST be
+ * present.
+ */
+ if (dp.getDistributionPoint() == null)
+ {
+ throw new AnnotatedException(
+ "CRL issuer is omitted from distribution point but no distributionPoint field present.");
+ }
+ // add and check issuer principals
+ for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); )
+ {
+ issuers.add((X500Principal)it.next());
+ }
+ }
+ // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
+ // distributionPoint
+// if (dp.getDistributionPoint() != null)
+// {
+// // look for nameRelativeToCRLIssuer
+// if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+// {
+// // append fragment to issuer, only one
+// // issuer can be there, if this is given
+// if (issuers.size() != 1)
+// {
+// throw new AnnotatedException(
+// "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+// }
+// ASN1Encodable relName = dp.getDistributionPoint().getName();
+// Iterator it = issuers.iterator();
+// List issuersTemp = new ArrayList(issuers.size());
+// while (it.hasNext())
+// {
+// Enumeration e = null;
+// try
+// {
+// e = ASN1Sequence.getInstance(
+// new ASN1InputStream(((X500Principal) it.next())
+// .getEncoded()).readObject()).getObjects();
+// }
+// catch (IOException ex)
+// {
+// throw new AnnotatedException(
+// "Cannot decode CRL issuer information.", ex);
+// }
+// ASN1EncodableVector v = new ASN1EncodableVector();
+// while (e.hasMoreElements())
+// {
+// v.add((ASN1Encodable) e.nextElement());
+// }
+// v.add(relName);
+// issuersTemp.add(new X500Principal(new DERSequence(v)
+// .getDEREncoded()));
+// }
+// issuers.clear();
+// issuers.addAll(issuersTemp);
+// }
+// }
+ Iterator it = issuers.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ selector.addIssuerName(((X500Principal)it.next()).getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException(
+ "Cannot decode CRL issuer information.", ex);
+ }
+ }
+ }
+
+ private static BigInteger getSerialNumber(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getSerialNumber();
+ }
+ else
+ {
+ return ((X509AttributeCertificate)cert).getSerialNumber();
+ }
+ }
+
+ protected static void getCertStatus(
+ Date validDate,
+ X509CRL crl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ X509CRLEntry crl_entry = null;
+
+ boolean isIndirect;
+ try
+ {
+ isIndirect = X509CRLObject.isIndirectCRL(crl);
+ }
+ catch (CRLException exception)
+ {
+ throw new AnnotatedException("Failed check for indirect CRL.", exception);
+ }
+
+ if (isIndirect)
+ {
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+
+ X500Principal certIssuer = crl_entry.getCertificateIssuer();
+
+ if (certIssuer == null)
+ {
+ certIssuer = getIssuerPrincipal(crl);
+ }
+
+ if (!getEncodedIssuerPrincipal(cert).equals(certIssuer))
+ {
+ return;
+ }
+ }
+ else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl)))
+ {
+ return; // not for our issuer, ignore
+ }
+ else
+ {
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+ }
+
+ DEREnumerated reasonCode = null;
+ if (crl_entry.hasExtensions())
+ {
+ try
+ {
+ reasonCode = DEREnumerated
+ .getInstance(CertPathValidatorUtilities
+ .getExtensionValue(crl_entry,
+ X509Extension.reasonCode.getId()));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Reason code CRL entry extension could not be decoded.",
+ e);
+ }
+ }
+
+ // for reason keyCompromise, caCompromise, aACompromise or
+ // unspecified
+ if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
+ || reasonCode == null
+ || reasonCode.getValue().intValue() == 0
+ || reasonCode.getValue().intValue() == 1
+ || reasonCode.getValue().intValue() == 2
+ || reasonCode.getValue().intValue() == 8)
+ {
+
+ // (i) or (j) (1)
+ if (reasonCode != null)
+ {
+ certStatus.setCertStatus(reasonCode.getValue().intValue());
+ }
+ // (i) or (j) (2)
+ else
+ {
+ certStatus.setCertStatus(CRLReason.unspecified);
+ }
+ certStatus.setRevocationDate(crl_entry.getRevocationDate());
+ }
+ }
+
+ /**
+ * Fetches delta CRLs according to RFC 3280 section 5.2.4.
+ *
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @param completeCRL The complete CRL the delta CRL is for.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the delta
+ * CRLs.
+ */
+ protected static Set getDeltaCRLs(Date currentDate,
+ ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
+ throws AnnotatedException
+ {
+
+ X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector();
+
+ // 5.2.4 (a)
+ try
+ {
+ deltaSelect.addIssuerName(CertPathValidatorUtilities
+ .getIssuerPrincipal(completeCRL).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL.", e);
+ }
+
+ BigInteger completeCRLNumber = null;
+ try
+ {
+ ASN1Primitive derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
+ CRL_NUMBER);
+ if (derObject != null)
+ {
+ completeCRLNumber = ASN1Integer.getInstance(derObject).getPositiveValue();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "CRL number extension could not be extracted from CRL.", e);
+ }
+
+ // 5.2.4 (b)
+ byte[] idp = null;
+ try
+ {
+ idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension value could not be read.",
+ e);
+ }
+
+ // 5.2.4 (d)
+
+ deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber
+ .add(BigInteger.valueOf(1)));
+
+ deltaSelect.setIssuingDistributionPoint(idp);
+ deltaSelect.setIssuingDistributionPointEnabled(true);
+
+ // 5.2.4 (c)
+ deltaSelect.setMaxBaseCRLNumber(completeCRLNumber);
+
+ // find delta CRLs
+ Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate);
+
+ Set result = new HashSet();
+
+ for (Iterator it = temp.iterator(); it.hasNext(); )
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (isDeltaCRL(crl))
+ {
+ result.add(crl);
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean isDeltaCRL(X509CRL crl)
+ {
+ Set critical = crl.getCriticalExtensionOIDs();
+
+ if (critical == null)
+ {
+ return false;
+ }
+
+ return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ }
+
+ /**
+ * Fetches complete CRLs according to RFC 3280.
+ *
+ * @param dp The distribution point for which the complete CRL
+ * @param cert The <code>X509Certificate</code> or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} for
+ * which the CRL should be searched.
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with complete
+ * CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the CRLs
+ * or no CRLs are found.
+ */
+ protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
+ Date currentDate, ExtendedPKIXParameters paramsPKIX)
+ throws AnnotatedException
+ {
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ try
+ {
+ Set issuers = new HashSet();
+ if (cert instanceof X509AttributeCertificate)
+ {
+ issuers.add(((X509AttributeCertificate)cert)
+ .getIssuer().getPrincipals()[0]);
+ }
+ else
+ {
+ issuers.add(getEncodedIssuerPrincipal(cert));
+ }
+ CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Could not get issuer information from distribution point.", e);
+ }
+ if (cert instanceof X509Certificate)
+ {
+ crlselect.setCertificateChecking((X509Certificate)cert);
+ }
+ else if (cert instanceof X509AttributeCertificate)
+ {
+ crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert);
+ }
+
+
+ crlselect.setCompleteCRLEnabled(true);
+
+ Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
+ if (crls.isEmpty())
+ {
+ if (cert instanceof X509AttributeCertificate)
+ {
+ X509AttributeCertificate aCert = (X509AttributeCertificate)cert;
+
+ throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\"");
+ }
+ else
+ {
+ X509Certificate xCert = (X509Certificate)cert;
+
+ throw new AnnotatedException("No CRLs found for issuer \"" + xCert.getIssuerX500Principal() + "\"");
+ }
+ }
+ return crls;
+ }
+
+ protected static Date getValidCertDateFromValidityModel(
+ ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index)
+ throws AnnotatedException
+ {
+ if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ // if end cert use given signing/encryption/... time
+ if (index <= 0)
+ {
+ return CertPathValidatorUtilities.getValidDate(paramsPKIX);
+ // else use time when previous cert was created
+ }
+ else
+ {
+ if (index - 1 == 0)
+ {
+ DERGeneralizedTime dateOfCertgen = null;
+ try
+ {
+ byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId());
+ if (extBytes != null)
+ {
+ dateOfCertgen = DERGeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ if (dateOfCertgen != null)
+ {
+ try
+ {
+ return dateOfCertgen.getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new AnnotatedException(
+ "Date from date of cert gen extension could not be parsed.",
+ e);
+ }
+ }
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ else
+ {
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ }
+ }
+ else
+ {
+ return getValidDate(paramsPKIX);
+ }
+ }
+
+ /**
+ * Return the next working key inheriting DSA parameters if necessary.
+ * <p>
+ * This methods inherits DSA parameters from the indexed certificate or
+ * previous certificates in the certificate chain to the returned
+ * <code>PublicKey</code>. The list is searched upwards, meaning the end
+ * certificate is at position 0 and previous certificates are following.
+ * </p>
+ * <p>
+ * If the indexed certificate does not contain a DSA key this method simply
+ * returns the public key. If the DSA key already contains DSA parameters
+ * the key is also only returned.
+ * </p>
+ *
+ * @param certs The certification path.
+ * @param index The index of the certificate which contains the public key
+ * which should be extended with DSA parameters.
+ * @return The public key of the certificate in list position
+ * <code>index</code> extended with DSA parameters if applicable.
+ * @throws AnnotatedException if DSA parameters cannot be inherited.
+ */
+ protected static PublicKey getNextWorkingKey(List certs, int index)
+ throws CertPathValidatorException
+ {
+ Certificate cert = (Certificate)certs.get(index);
+ PublicKey pubKey = cert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ return pubKey;
+ }
+ DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey;
+ if (dsaPubKey.getParams() != null)
+ {
+ return dsaPubKey;
+ }
+ for (int i = index + 1; i < certs.size(); i++)
+ {
+ X509Certificate parentCert = (X509Certificate)certs.get(i);
+ pubKey = parentCert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ throw new CertPathValidatorException(
+ "DSA parameters cannot be inherited from previous certificate.");
+ }
+ DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey;
+ if (prevDSAPubKey.getParams() == null)
+ {
+ continue;
+ }
+ DSAParams dsaParams = prevDSAPubKey.getParams();
+ DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
+ dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+ try
+ {
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
+ return keyFactory.generatePublic(dsaPubKeySpec);
+ }
+ catch (Exception exception)
+ {
+ throw new RuntimeException(exception.getMessage());
+ }
+ }
+ throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ /**
+ * Find the issuer certificates of a given certificate.
+ *
+ * @param cert The certificate for which an issuer should be found.
+ * @param pkixParams
+ * @return A <code>Collection</code> object containing the issuer
+ * <code>X509Certificate</code>s. Never <code>null</code>.
+ * @throws AnnotatedException if an error occurs.
+ */
+ protected static Collection findIssuerCerts(
+ X509Certificate cert,
+ ExtendedPKIXBuilderParameters pkixParams)
+ throws AnnotatedException
+ {
+ X509CertStoreSelector certSelect = new X509CertStoreSelector();
+ Set certs = new HashSet();
+ try
+ {
+ certSelect.setSubject(cert.getIssuerX500Principal().getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+ }
+
+ Iterator iter;
+
+ try
+ {
+ List matches = new ArrayList();
+
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getCertStores()));
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getStores()));
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getAdditionalStores()));
+
+ iter = matches.iterator();
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate cannot be searched.", e);
+ }
+
+ X509Certificate issuer = null;
+ while (iter.hasNext())
+ {
+ issuer = (X509Certificate)iter.next();
+ // issuer cannot be verified because possible DSA inheritance
+ // parameters are missing
+ certs.add(issuer);
+ }
+ return certs;
+ }
+
+ protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
+ String sigProvider)
+ throws GeneralSecurityException
+ {
+ if (sigProvider == null)
+ {
+ cert.verify(publicKey);
+ }
+ else
+ {
+ cert.verify(publicKey, sigProvider);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertStatus.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertStatus.java
new file mode 100644
index 000000000..531f340eb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertStatus.java
@@ -0,0 +1,46 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Date;
+
+class CertStatus
+{
+ public static final int UNREVOKED = 11;
+
+ public static final int UNDETERMINED = 12;
+
+ int certStatus = UNREVOKED;
+
+ Date revocationDate = null;
+
+ /**
+ * @return Returns the revocationDate.
+ */
+ public Date getRevocationDate()
+ {
+ return revocationDate;
+ }
+
+ /**
+ * @param revocationDate The revocationDate to set.
+ */
+ public void setRevocationDate(Date revocationDate)
+ {
+ this.revocationDate = revocationDate;
+ }
+
+ /**
+ * @return Returns the certStatus.
+ */
+ public int getCertStatus()
+ {
+ return certStatus;
+ }
+
+ /**
+ * @param certStatus The certStatus to set.
+ */
+ public void setCertStatus(int certStatus)
+ {
+ this.certStatus = certStatus;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertStoreCollectionSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertStoreCollectionSpi.java
new file mode 100644
index 000000000..5467e16e4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/CertStoreCollectionSpi.java
@@ -0,0 +1,104 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import java.security.cert.CollectionCertStoreParameters;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+public class CertStoreCollectionSpi extends CertStoreSpi
+{
+ private CollectionCertStoreParameters params;
+
+ public CertStoreCollectionSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof CollectionCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.CertStoreCollectionSpi: parameter must be a CollectionCertStoreParameters object\n" + params.toString());
+ }
+
+ this.params = (CollectionCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(
+ CertSelector selector)
+ throws CertStoreException
+ {
+ List col = new ArrayList();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof Certificate)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof Certificate) && selector.match((Certificate)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+
+
+ public Collection engineGetCRLs(
+ CRLSelector selector)
+ throws CertStoreException
+ {
+ List col = new ArrayList();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof CRL)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof CRL) && selector.match((CRL)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/DHUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/DHUtil.java
new file mode 100644
index 000000000..deea1773b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/DHUtil.java
@@ -0,0 +1,50 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.DHParameters;
+import org.spongycastle.crypto.params.DHPrivateKeyParameters;
+import org.spongycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DH objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class DHUtil
+{
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPublicKey)
+ {
+ DHPublicKey k = (DHPublicKey)key;
+
+ return new DHPublicKeyParameters(k.getY(),
+ new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+ }
+
+ throw new InvalidKeyException("can't identify DH public key.");
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)key;
+
+ return new DHPrivateKeyParameters(k.getX(),
+ new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+ }
+
+ throw new InvalidKeyException("can't identify DH private key.");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/ExtCRLException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/ExtCRLException.java
new file mode 100644
index 000000000..11e2d7fdc
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/ExtCRLException.java
@@ -0,0 +1,20 @@
+package org.spongycastle.jce.provider;
+
+import java.security.cert.CRLException;
+
+class ExtCRLException
+ extends CRLException
+{
+ Throwable cause;
+
+ ExtCRLException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEDHPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEDHPrivateKey.java
new file mode 100644
index 000000000..5fca7fbdd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEDHPrivateKey.java
@@ -0,0 +1,188 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.pkcs.DHParameter;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.DHDomainParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.DHPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JCEDHPrivateKey
+ implements DHPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 311058815616901812L;
+
+ BigInteger x;
+
+ private DHParameterSpec dhSpec;
+ private PrivateKeyInfo info;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JCEDHPrivateKey()
+ {
+ }
+
+ JCEDHPrivateKey(
+ DHPrivateKey key)
+ {
+ this.x = key.getX();
+ this.dhSpec = key.getParams();
+ }
+
+ JCEDHPrivateKey(
+ DHPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ }
+
+ JCEDHPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
+ DERInteger derX = DERInteger.getInstance(info.parsePrivateKey());
+ DERObjectIdentifier id = info.getAlgorithmId().getAlgorithm();
+
+ this.info = info;
+ this.x = derX.getValue();
+
+ if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ DHParameter params = DHParameter.getInstance(seq);
+
+ if (params.getL() != null)
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+ }
+ else
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ }
+ }
+ else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+ this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm type: " + id);
+ }
+ }
+
+ JCEDHPrivateKey(
+ DHPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DH";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ if (info != null)
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+
+ PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new DERInteger(getX()));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return dhSpec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ x = (BigInteger)in.readObject();
+
+ this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getX());
+ out.writeObject(dhSpec.getP());
+ out.writeObject(dhSpec.getG());
+ out.writeInt(dhSpec.getL());
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEDHPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEDHPublicKey.java
new file mode 100644
index 000000000..ac8500962
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEDHPublicKey.java
@@ -0,0 +1,178 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.pkcs.DHParameter;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.DHDomainParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.DHPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class JCEDHPublicKey
+ implements DHPublicKey
+{
+ static final long serialVersionUID = -216691575254424324L;
+
+ private BigInteger y;
+ private DHParameterSpec dhSpec;
+ private SubjectPublicKeyInfo info;
+
+ JCEDHPublicKey(
+ DHPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ }
+
+ JCEDHPublicKey(
+ DHPublicKey key)
+ {
+ this.y = key.getY();
+ this.dhSpec = key.getParams();
+ }
+
+ JCEDHPublicKey(
+ DHPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ }
+
+ JCEDHPublicKey(
+ BigInteger y,
+ DHParameterSpec dhSpec)
+ {
+ this.y = y;
+ this.dhSpec = dhSpec;
+ }
+
+ JCEDHPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ this.info = info;
+
+ DERInteger derY;
+ try
+ {
+ derY = (DERInteger)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DH public key");
+ }
+
+ this.y = derY.getValue();
+
+ ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
+ DERObjectIdentifier id = info.getAlgorithmId().getAlgorithm();
+
+ // we need the PKCS check to handle older keys marked with the X9 oid.
+ if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
+ {
+ DHParameter params = DHParameter.getInstance(seq);
+
+ if (params.getL() != null)
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+ }
+ else
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ }
+ }
+ else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+ this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm type: " + id);
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return "DH";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (info != null)
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new DERInteger(y));
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return dhSpec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ private boolean isPKCSParam(ASN1Sequence seq)
+ {
+ if (seq.size() == 2)
+ {
+ return true;
+ }
+
+ if (seq.size() > 3)
+ {
+ return false;
+ }
+
+ DERInteger l = DERInteger.getInstance(seq.getObjectAt(2));
+ DERInteger p = DERInteger.getInstance(seq.getObjectAt(0));
+
+ if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.y = (BigInteger)in.readObject();
+ this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getY());
+ out.writeObject(dhSpec.getP());
+ out.writeObject(dhSpec.getG());
+ out.writeInt(dhSpec.getL());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEECPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEECPrivateKey.java
new file mode 100644
index 000000000..f4acffcde
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEECPrivateKey.java
@@ -0,0 +1,478 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.sec.ECPrivateKeyStructure;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class JCEECPrivateKey
+ implements ECPrivateKey, org.spongycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ private String algorithm = "EC";
+ private BigInteger d;
+ private ECParameterSpec ecSpec;
+ private boolean withCompression;
+
+ private DERBitString publicKey;
+
+ private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JCEECPrivateKey()
+ {
+ }
+
+ public JCEECPrivateKey(
+ ECPrivateKey key)
+ {
+ this.d = key.getS();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ org.spongycastle.jce.spec.ECPrivateKeySpec spec)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getD();
+
+ if (spec.getParams() != null) // can be null if implicitlyCA
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve;
+
+ ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ this.ecSpec = null;
+ }
+ }
+
+
+ public JCEECPrivateKey(
+ String algorithm,
+ ECPrivateKeySpec spec)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getS();
+ this.ecSpec = spec.getParams();
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ JCEECPrivateKey key)
+ {
+ this.algorithm = algorithm;
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.attrCarrier = key.attrCarrier;
+ this.publicKey = key.publicKey;
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ JCEECPublicKey pubKey,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ JCEECPublicKey pubKey,
+ org.spongycastle.jce.spec.ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(),
+ spec.getH().intValue());
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ }
+
+ JCEECPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ populateFromPrivKeyInfo(info);
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ throws IOException
+ {
+ X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ if (ecP == null) // GOST Curve
+ {
+ ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECGOST3410NamedCurves.getName(oid),
+ ellipticCurve,
+ new ECPoint(
+ gParam.getG().getAffineXCoord().toBigInteger(),
+ gParam.getG().getAffineYCoord().toBigInteger()),
+ gParam.getN(),
+ gParam.getH());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECUtil.getCurveName(oid),
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH());
+ }
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ ASN1Encodable privKey = info.parsePrivateKey();
+ if (privKey instanceof DERInteger)
+ {
+ DERInteger derD = DERInteger.getInstance(privKey);
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)privKey);
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ X962Parameters params;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null) // guess it's the OID
+ {
+ curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ ECPrivateKeyStructure keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getS(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getS(), params);
+ }
+
+ try
+ {
+ if (algorithm.equals("ECGOST3410"))
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+ }
+ else
+ {
+
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+ }
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.spongycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null)
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public BigInteger getS()
+ {
+ return d;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof JCEECPrivateKey))
+ {
+ return false;
+ }
+
+ JCEECPrivateKey other = (JCEECPrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Private Key").append(nl);
+ buf.append(" S: ").append(this.d.toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ private DERBitString getPublicKeyDetails(JCEECPublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.algorithm = (String)in.readObject();
+ this.withCompression = in.readBoolean();
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ attrCarrier.readObject(in);
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getEncoded());
+ out.writeObject(algorithm);
+ out.writeBoolean(withCompression);
+
+ attrCarrier.writeObject(out);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEECPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEECPublicKey.java
new file mode 100644
index 000000000..08c640dbb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEECPublicKey.java
@@ -0,0 +1,525 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ECPoint;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveSpec;
+import org.spongycastle.math.ec.ECCurve;
+
+public class JCEECPublicKey
+ implements ECPublicKey, org.spongycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+ private String algorithm = "EC";
+ private org.spongycastle.math.ec.ECPoint q;
+ private ECParameterSpec ecSpec;
+ private boolean withCompression;
+ private GOST3410PublicKeyAlgParameters gostParams;
+
+ public JCEECPublicKey(
+ String algorithm,
+ JCEECPublicKey key)
+ {
+ this.algorithm = algorithm;
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.gostParams = key.gostParams;
+ }
+
+ public JCEECPublicKey(
+ String algorithm,
+ ECPublicKeySpec spec)
+ {
+ this.algorithm = algorithm;
+ this.ecSpec = spec.getParams();
+ this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ }
+
+ public JCEECPublicKey(
+ String algorithm,
+ org.spongycastle.jce.spec.ECPublicKeySpec spec)
+ {
+ this.algorithm = algorithm;
+ this.q = spec.getQ();
+
+ if (spec.getParams() != null) // can be null if implictlyCa
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.spongycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger(), false);
+ }
+ this.ecSpec = null;
+ }
+ }
+
+ public JCEECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+ }
+
+ public JCEECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ org.spongycastle.jce.spec.ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+ }
+ }
+
+ /*
+ * called for implicitCA
+ */
+ public JCEECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ }
+
+ private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+ {
+ return new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getAffineXCoord().toBigInteger(),
+ dp.getG().getAffineYCoord().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+
+ public JCEECPublicKey(
+ ECPublicKey key)
+ {
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+ }
+
+ JCEECPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ populateFromPubKeyInfo(info);
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ DERBitString bits = info.getPublicKeyData();
+ ASN1OctetString key;
+ this.algorithm = "ECGOST3410";
+
+ try
+ {
+ key = (ASN1OctetString) ASN1Primitive.fromByteArray(bits.getBytes());
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+
+ byte[] keyEnc = key.getOctets();
+ byte[] x = new byte[32];
+ byte[] y = new byte[32];
+
+ for (int i = 0; i != x.length; i++)
+ {
+ x[i] = keyEnc[32 - 1 - i];
+ }
+
+ for (int i = 0; i != y.length; i++)
+ {
+ y[i] = keyEnc[64 - 1 - i];
+ }
+
+ gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+
+ ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+
+ ECCurve curve = spec.getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
+
+ this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
+
+ ecSpec = new ECNamedCurveSpec(
+ ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getAffineXCoord().toBigInteger(),
+ spec.getG().getAffineYCoord().toBigInteger()),
+ spec.getN(), spec.getH());
+
+ }
+ else
+ {
+ X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithmId().getParameters());
+ ECCurve curve;
+ EllipticCurve ellipticCurve;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ curve = ecP.getCurve();
+ ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECUtil.getCurveName(oid),
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ curve = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve();
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+
+ curve = ecP.getCurve();
+ ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getAffineXCoord().toBigInteger(),
+ ecP.getG().getAffineYCoord().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ DERBitString bits = info.getPublicKeyData();
+ byte[] data = bits.getBytes();
+ ASN1OctetString key = new DEROctetString(data);
+
+ //
+ // extra octet string - one of our old certs...
+ //
+ if (data[0] == 0x04 && data[1] == data.length - 2
+ && (data[2] == 0x02 || data[2] == 0x03))
+ {
+ int qLength = new X9IntegerConverter().getByteLength(curve);
+
+ if (qLength >= data.length - 3)
+ {
+ try
+ {
+ key = (ASN1OctetString) ASN1Primitive.fromByteArray(data);
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+ }
+ X9ECPoint derQ = new X9ECPoint(curve, key);
+
+ this.q = derQ.getPoint();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ ASN1Encodable params;
+ SubjectPublicKeyInfo info;
+
+ if (algorithm.equals("ECGOST3410"))
+ {
+ if (gostParams != null)
+ {
+ params = gostParams;
+ }
+ else
+ {
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ params = new GOST3410PublicKeyAlgParameters(
+ ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
+ CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
+ }
+ else
+ { // strictly speaking this may not be applicable...
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+ }
+
+ BigInteger bX = this.q.getAffineXCoord().toBigInteger();
+ BigInteger bY = this.q.getAffineYCoord().toBigInteger();
+ byte[] encKey = new byte[64];
+
+ extractBytes(encKey, 0, bX);
+ extractBytes(encKey, 32, bY);
+
+ try
+ {
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null)
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECCurve curve = this.engineGetQ().getCurve();
+ ASN1OctetString p = (ASN1OctetString)
+ new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive();
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+ {
+ byte[] val = bI.toByteArray();
+ if (val.length < 32)
+ {
+ byte[] tmp = new byte[32];
+ System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+ val = tmp;
+ }
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[offSet + i] = val[val.length - 1 - i];
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.spongycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null) // implictlyCA
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ public ECPoint getW()
+ {
+ return new ECPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger());
+ }
+
+ public org.spongycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.spongycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.spongycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord());
+ }
+ else
+ {
+ return new org.spongycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord());
+ }
+ }
+
+ return q;
+ }
+
+ public org.spongycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.q.getAffineYCoord().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof JCEECPublicKey))
+ {
+ return false;
+ }
+
+ JCEECPublicKey other = (JCEECPublicKey)o;
+
+ return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.algorithm = (String)in.readObject();
+ this.withCompression = in.readBoolean();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getEncoded());
+ out.writeObject(algorithm);
+ out.writeBoolean(withCompression);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEElGamalPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEElGamalPrivateKey.java
new file mode 100644
index 000000000..096da0cf4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEElGamalPrivateKey.java
@@ -0,0 +1,167 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.oiw.ElGamalParameter;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.ElGamalPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.ElGamalPrivateKey;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.spec.ElGamalParameterSpec;
+import org.spongycastle.jce.spec.ElGamalPrivateKeySpec;
+
+public class JCEElGamalPrivateKey
+ implements ElGamalPrivateKey, DHPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 4819350091141529678L;
+
+ BigInteger x;
+
+ ElGamalParameterSpec elSpec;
+
+ private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JCEElGamalPrivateKey()
+ {
+ }
+
+ JCEElGamalPrivateKey(
+ ElGamalPrivateKey key)
+ {
+ this.x = key.getX();
+ this.elSpec = key.getParameters();
+ }
+
+ JCEElGamalPrivateKey(
+ DHPrivateKey key)
+ {
+ this.x = key.getX();
+ this.elSpec = new ElGamalParameterSpec(key.getParams().getP(), key.getParams().getG());
+ }
+
+ JCEElGamalPrivateKey(
+ ElGamalPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.elSpec = new ElGamalParameterSpec(spec.getParams().getP(), spec.getParams().getG());
+ }
+
+ JCEElGamalPrivateKey(
+ DHPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG());
+ }
+
+ JCEElGamalPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ ElGamalParameter params = new ElGamalParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+ DERInteger derX = ASN1Integer.getInstance(info.parsePrivateKey());
+
+ this.x = derX.getValue();
+ this.elSpec = new ElGamalParameterSpec(params.getP(), params.getG());
+ }
+
+ JCEElGamalPrivateKey(
+ ElGamalPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.elSpec = new ElGamalParameterSpec(params.getParameters().getP(), params.getParameters().getG());
+ }
+
+ public String getAlgorithm()
+ {
+ return "ElGamal";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(elSpec.getP(), elSpec.getG())), new DERInteger(getX()));
+ }
+
+ public ElGamalParameterSpec getParameters()
+ {
+ return elSpec;
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return new DHParameterSpec(elSpec.getP(), elSpec.getG());
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ x = (BigInteger)in.readObject();
+
+ this.elSpec = new ElGamalParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getX());
+ out.writeObject(elSpec.getP());
+ out.writeObject(elSpec.getG());
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEElGamalPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEElGamalPublicKey.java
new file mode 100644
index 000000000..83b24629a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEElGamalPublicKey.java
@@ -0,0 +1,140 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.oiw.ElGamalParameter;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.params.ElGamalPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jce.interfaces.ElGamalPublicKey;
+import org.spongycastle.jce.spec.ElGamalParameterSpec;
+import org.spongycastle.jce.spec.ElGamalPublicKeySpec;
+
+public class JCEElGamalPublicKey
+ implements ElGamalPublicKey, DHPublicKey
+{
+ static final long serialVersionUID = 8712728417091216948L;
+
+ private BigInteger y;
+ private ElGamalParameterSpec elSpec;
+
+ JCEElGamalPublicKey(
+ ElGamalPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.elSpec = new ElGamalParameterSpec(spec.getParams().getP(), spec.getParams().getG());
+ }
+
+ JCEElGamalPublicKey(
+ DHPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG());
+ }
+
+ JCEElGamalPublicKey(
+ ElGamalPublicKey key)
+ {
+ this.y = key.getY();
+ this.elSpec = key.getParameters();
+ }
+
+ JCEElGamalPublicKey(
+ DHPublicKey key)
+ {
+ this.y = key.getY();
+ this.elSpec = new ElGamalParameterSpec(key.getParams().getP(), key.getParams().getG());
+ }
+
+ JCEElGamalPublicKey(
+ ElGamalPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.elSpec = new ElGamalParameterSpec(params.getParameters().getP(), params.getParameters().getG());
+ }
+
+ JCEElGamalPublicKey(
+ BigInteger y,
+ ElGamalParameterSpec elSpec)
+ {
+ this.y = y;
+ this.elSpec = elSpec;
+ }
+
+ JCEElGamalPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ ElGamalParameter params = new ElGamalParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+ DERInteger derY = null;
+
+ try
+ {
+ derY = (DERInteger)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DSA public key");
+ }
+
+ this.y = derY.getValue();
+ this.elSpec = new ElGamalParameterSpec(params.getP(), params.getG());
+ }
+
+ public String getAlgorithm()
+ {
+ return "ElGamal";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(elSpec.getP(), elSpec.getG())), new DERInteger(y));
+ }
+
+ public ElGamalParameterSpec getParameters()
+ {
+ return elSpec;
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return new DHParameterSpec(elSpec.getP(), elSpec.getG());
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.y = (BigInteger)in.readObject();
+ this.elSpec = new ElGamalParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getY());
+ out.writeObject(elSpec.getP());
+ out.writeObject(elSpec.getG());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPrivateCrtKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPrivateCrtKey.java
new file mode 100644
index 000000000..595080297
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPrivateCrtKey.java
@@ -0,0 +1,241 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.RSAPrivateKey;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+/**
+ * A provider representation for a RSA private key, with CRT factors included.
+ */
+public class JCERSAPrivateCrtKey
+ extends JCERSAPrivateKey
+ implements RSAPrivateCrtKey
+{
+ static final long serialVersionUID = 7834723820638524718L;
+
+ private BigInteger publicExponent;
+ private BigInteger primeP;
+ private BigInteger primeQ;
+ private BigInteger primeExponentP;
+ private BigInteger primeExponentQ;
+ private BigInteger crtCoefficient;
+
+ /**
+ * construct a private key from it's org.spongycastle.crypto equivalent.
+ *
+ * @param key the parameters object representing the private key.
+ */
+ JCERSAPrivateCrtKey(
+ RSAPrivateCrtKeyParameters key)
+ {
+ super(key);
+
+ this.publicExponent = key.getPublicExponent();
+ this.primeP = key.getP();
+ this.primeQ = key.getQ();
+ this.primeExponentP = key.getDP();
+ this.primeExponentQ = key.getDQ();
+ this.crtCoefficient = key.getQInv();
+ }
+
+ /**
+ * construct a private key from an RSAPrivateCrtKeySpec
+ *
+ * @param spec the spec to be used in construction.
+ */
+ JCERSAPrivateCrtKey(
+ RSAPrivateCrtKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ this.privateExponent = spec.getPrivateExponent();
+ this.primeP = spec.getPrimeP();
+ this.primeQ = spec.getPrimeQ();
+ this.primeExponentP = spec.getPrimeExponentP();
+ this.primeExponentQ = spec.getPrimeExponentQ();
+ this.crtCoefficient = spec.getCrtCoefficient();
+ }
+
+ /**
+ * construct a private key from another RSAPrivateCrtKey.
+ *
+ * @param key the object implementing the RSAPrivateCrtKey interface.
+ */
+ JCERSAPrivateCrtKey(
+ RSAPrivateCrtKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrimeP();
+ this.primeQ = key.getPrimeQ();
+ this.primeExponentP = key.getPrimeExponentP();
+ this.primeExponentQ = key.getPrimeExponentQ();
+ this.crtCoefficient = key.getCrtCoefficient();
+ }
+
+ /**
+ * construct an RSA key from a private key info object.
+ */
+ JCERSAPrivateCrtKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ this(org.spongycastle.asn1.pkcs.RSAPrivateKey.getInstance(info.parsePrivateKey()));
+ }
+
+ /**
+ * construct an RSA key from a ASN.1 RSA private key object.
+ */
+ JCERSAPrivateCrtKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrime1();
+ this.primeQ = key.getPrime2();
+ this.primeExponentP = key.getExponent1();
+ this.primeExponentQ = key.getExponent2();
+ this.crtCoefficient = key.getCoefficient();
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the encoding format we produce in getEncoded().
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ /**
+ * return the prime P.
+ *
+ * @return the prime P.
+ */
+ public BigInteger getPrimeP()
+ {
+ return primeP;
+ }
+
+ /**
+ * return the prime Q.
+ *
+ * @return the prime Q.
+ */
+ public BigInteger getPrimeQ()
+ {
+ return primeQ;
+ }
+
+ /**
+ * return the prime exponent for P.
+ *
+ * @return the prime exponent for P.
+ */
+ public BigInteger getPrimeExponentP()
+ {
+ return primeExponentP;
+ }
+
+ /**
+ * return the prime exponent for Q.
+ *
+ * @return the prime exponent for Q.
+ */
+ public BigInteger getPrimeExponentQ()
+ {
+ return primeExponentQ;
+ }
+
+ /**
+ * return the CRT coefficient.
+ *
+ * @return the CRT coefficient.
+ */
+ public BigInteger getCrtCoefficient()
+ {
+ return crtCoefficient;
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode()
+ ^ this.getPublicExponent().hashCode()
+ ^ this.getPrivateExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPrivateCrtKey))
+ {
+ return false;
+ }
+
+ RSAPrivateCrtKey key = (RSAPrivateCrtKey)o;
+
+ return this.getModulus().equals(key.getModulus())
+ && this.getPublicExponent().equals(key.getPublicExponent())
+ && this.getPrivateExponent().equals(key.getPrivateExponent())
+ && this.getPrimeP().equals(key.getPrimeP())
+ && this.getPrimeQ().equals(key.getPrimeQ())
+ && this.getPrimeExponentP().equals(key.getPrimeExponentP())
+ && this.getPrimeExponentQ().equals(key.getPrimeExponentQ())
+ && this.getCrtCoefficient().equals(key.getCrtCoefficient());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Private CRT Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+ buf.append(" private exponent: ").append(this.getPrivateExponent().toString(16)).append(nl);
+ buf.append(" primeP: ").append(this.getPrimeP().toString(16)).append(nl);
+ buf.append(" primeQ: ").append(this.getPrimeQ().toString(16)).append(nl);
+ buf.append(" primeExponentP: ").append(this.getPrimeExponentP().toString(16)).append(nl);
+ buf.append(" primeExponentQ: ").append(this.getPrimeExponentQ().toString(16)).append(nl);
+ buf.append(" crtCoefficient: ").append(this.getCrtCoefficient().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPrivateKey.java
new file mode 100644
index 000000000..f7f6f88f1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPrivateKey.java
@@ -0,0 +1,146 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JCERSAPrivateKey
+ implements RSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 5110188922551353628L;
+
+ private static BigInteger ZERO = BigInteger.valueOf(0);
+
+ protected BigInteger modulus;
+ protected BigInteger privateExponent;
+
+ private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JCERSAPrivateKey()
+ {
+ }
+
+ JCERSAPrivateKey(
+ RSAKeyParameters key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getExponent();
+ }
+
+ JCERSAPrivateKey(
+ RSAPrivateKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.privateExponent = spec.getPrivateExponent();
+ }
+
+ JCERSAPrivateKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getPrivateExponent();
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPrivateExponent()
+ {
+ return privateExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.spongycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof RSAPrivateKey))
+ {
+ return false;
+ }
+
+ if (o == this)
+ {
+ return true;
+ }
+
+ RSAPrivateKey key = (RSAPrivateKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPrivateExponent().equals(key.getPrivateExponent());
+ }
+
+ public int hashCode()
+ {
+ return getModulus().hashCode() ^ getPrivateExponent().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.modulus = (BigInteger)in.readObject();
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ attrCarrier.readObject(in);
+
+ this.privateExponent = (BigInteger)in.readObject();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(modulus);
+
+ attrCarrier.writeObject(out);
+
+ out.writeObject(privateExponent);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPublicKey.java
new file mode 100644
index 000000000..63d142950
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCERSAPublicKey.java
@@ -0,0 +1,131 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.RSAPublicKeyStructure;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class JCERSAPublicKey
+ implements RSAPublicKey
+{
+ static final long serialVersionUID = 2675817738516720772L;
+
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+
+ JCERSAPublicKey(
+ RSAKeyParameters key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getExponent();
+ }
+
+ JCERSAPublicKey(
+ RSAPublicKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ }
+
+ JCERSAPublicKey(
+ RSAPublicKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ }
+
+ JCERSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ RSAPublicKeyStructure pubKey = new RSAPublicKeyStructure((ASN1Sequence)info.parsePublicKey());
+
+ this.modulus = pubKey.getModulus();
+ this.publicExponent = pubKey.getPublicExponent();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in RSA public key");
+ }
+ }
+
+ /**
+ * return the modulus.
+ *
+ * @return the modulus.
+ */
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKeyStructure(getModulus(), getPublicExponent()));
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPublicKey))
+ {
+ return false;
+ }
+
+ RSAPublicKey key = (RSAPublicKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPublicExponent().equals(key.getPublicExponent());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Public Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEStreamCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEStreamCipher.java
new file mode 100644
index 000000000..e395045c5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JCEStreamCipher.java
@@ -0,0 +1,613 @@
+package org.spongycastle.jce.provider;
+
+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.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DataLengthException;
+import org.spongycastle.crypto.StreamBlockCipher;
+import org.spongycastle.crypto.StreamCipher;
+import org.spongycastle.crypto.engines.BlowfishEngine;
+import org.spongycastle.crypto.engines.DESEngine;
+import org.spongycastle.crypto.engines.DESedeEngine;
+import org.spongycastle.crypto.engines.RC4Engine;
+import org.spongycastle.crypto.engines.SkipjackEngine;
+import org.spongycastle.crypto.engines.TwofishEngine;
+import org.spongycastle.crypto.modes.CFBBlockCipher;
+import org.spongycastle.crypto.modes.OFBBlockCipher;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.symmetric.util.PBE;
+
+public class JCEStreamCipher
+ extends CipherSpi
+ implements PBE
+{
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ RC2ParameterSpec.class,
+ RC5ParameterSpec.class,
+ IvParameterSpec.class,
+ PBEParameterSpec.class
+ };
+
+ private StreamCipher cipher;
+ private ParametersWithIV ivParam;
+
+ private int ivLength = 0;
+
+ private PBEParameterSpec pbeSpec = null;
+ private String pbeAlgorithm = null;
+
+ private AlgorithmParameters engineParams;
+
+ protected JCEStreamCipher(
+ StreamCipher engine,
+ int ivLength)
+ {
+ cipher = engine;
+ this.ivLength = ivLength;
+ }
+
+ protected JCEStreamCipher(
+ BlockCipher engine,
+ int ivLength)
+ {
+ this.ivLength = ivLength;
+
+ cipher = new StreamBlockCipher(engine);
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return 0;
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return (ivParam != null) ? ivParam.getIV() : null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length * 8;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return inputLen;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (pbeSpec != null)
+ {
+ try
+ {
+ AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(pbeSpec);
+
+ return engineParams;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ /**
+ * should never be called.
+ */
+ protected void engineSetMode(
+ String mode)
+ {
+ if (!mode.equalsIgnoreCase("ECB"))
+ {
+ throw new IllegalArgumentException("can't support mode " + mode);
+ }
+ }
+
+ /**
+ * should never be called.
+ */
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ if (!padding.equalsIgnoreCase("NoPadding"))
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ this.pbeSpec = null;
+ this.pbeAlgorithm = null;
+
+ this.engineParams = null;
+
+ //
+ // basic key check
+ //
+ if (!(key instanceof SecretKey))
+ {
+ throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+ }
+
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (k.getOID() != null)
+ {
+ pbeAlgorithm = k.getOID().getId();
+ }
+ else
+ {
+ pbeAlgorithm = k.getAlgorithm();
+ }
+
+ if (k.getParam() != null)
+ {
+ param = k.getParam();
+ pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
+ }
+ else if (params instanceof PBEParameterSpec)
+ {
+ param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName());
+ pbeSpec = (PBEParameterSpec)params;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+
+ if (k.getIvSize() != 0)
+ {
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown parameter type.");
+ }
+
+ if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+ {
+ SecureRandom ivRandom = random;
+
+ if (ivRandom == null)
+ {
+ ivRandom = new SecureRandom();
+ }
+
+ if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+ {
+ byte[] iv = new byte[ivLength];
+
+ ivRandom.nextBytes(iv);
+ param = new ParametersWithIV(param, iv);
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("no IV set when one expected");
+ }
+ }
+
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ System.out.println("eeek!");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ for (int i = 0; i != availableSpecs.length; i++)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(availableSpecs[i]);
+ break;
+ }
+ catch (Exception e)
+ {
+ continue;
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineInit(opmode, key, paramSpec, random);
+ engineParams = 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());
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ byte[] out = new byte[inputLen];
+
+ cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+ return out;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ try
+ {
+ cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+
+ return inputLen;
+ }
+ catch (DataLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws BadPaddingException, IllegalBlockSizeException
+ {
+ if (inputLen != 0)
+ {
+ byte[] out = engineUpdate(input, inputOffset, inputLen);
+
+ cipher.reset();
+
+ return out;
+ }
+
+ cipher.reset();
+
+ return new byte[0];
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws BadPaddingException
+ {
+ if (inputLen != 0)
+ {
+ cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ cipher.reset();
+
+ return inputLen;
+ }
+
+ protected byte[] engineWrap(
+ Key key)
+ throws IllegalBlockSizeException, InvalidKeyException
+ {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null)
+ {
+ throw new InvalidKeyException("Cannot wrap key, null encoding.");
+ }
+
+ try
+ {
+ return engineDoFinal(encoded, 0, encoded.length);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ }
+
+ protected Key engineUnwrap(
+ byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException
+ {
+ byte[] encoded;
+ try
+ {
+ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ catch (IllegalBlockSizeException e2)
+ {
+ throw new InvalidKeyException(e2.getMessage());
+ }
+
+ if (wrappedKeyType == Cipher.SECRET_KEY)
+ {
+ return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+ }
+ else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ /*
+ * The caller doesn't know the algorithm as it is part of
+ * the encrypted data.
+ */
+ try
+ {
+ PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded);
+
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+ if (privKey != null)
+ {
+ return privKey;
+ }
+ else
+ {
+ throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("Invalid key encoding.");
+ }
+ }
+ else
+ {
+ try
+ {
+ KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+ if (wrappedKeyType == Cipher.PUBLIC_KEY)
+ {
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ }
+ else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+ {
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ }
+ catch (InvalidKeySpecException e2)
+ {
+ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+ }
+
+ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+ }
+ }
+
+ /*
+ * The ciphers that inherit from us.
+ */
+
+ /**
+ * DES
+ */
+ static public class DES_CFB8
+ extends JCEStreamCipher
+ {
+ public DES_CFB8()
+ {
+ super(new CFBBlockCipher(new DESEngine(), 8), 64);
+ }
+ }
+
+ /**
+ * DESede
+ */
+ static public class DESede_CFB8
+ extends JCEStreamCipher
+ {
+ public DESede_CFB8()
+ {
+ super(new CFBBlockCipher(new DESedeEngine(), 8), 64);
+ }
+ }
+
+ /**
+ * SKIPJACK
+ */
+ static public class Skipjack_CFB8
+ extends JCEStreamCipher
+ {
+ public Skipjack_CFB8()
+ {
+ super(new CFBBlockCipher(new SkipjackEngine(), 8), 64);
+ }
+ }
+
+ /**
+ * Blowfish
+ */
+ static public class Blowfish_CFB8
+ extends JCEStreamCipher
+ {
+ public Blowfish_CFB8()
+ {
+ super(new CFBBlockCipher(new BlowfishEngine(), 8), 64);
+ }
+ }
+
+ /**
+ * Twofish
+ */
+ static public class Twofish_CFB8
+ extends JCEStreamCipher
+ {
+ public Twofish_CFB8()
+ {
+ super(new CFBBlockCipher(new TwofishEngine(), 8), 128);
+ }
+ }
+
+ /**
+ * DES
+ */
+ static public class DES_OFB8
+ extends JCEStreamCipher
+ {
+ public DES_OFB8()
+ {
+ super(new OFBBlockCipher(new DESEngine(), 8), 64);
+ }
+ }
+
+ /**
+ * DESede
+ */
+ static public class DESede_OFB8
+ extends JCEStreamCipher
+ {
+ public DESede_OFB8()
+ {
+ super(new OFBBlockCipher(new DESedeEngine(), 8), 64);
+ }
+ }
+
+ /**
+ * SKIPJACK
+ */
+ static public class Skipjack_OFB8
+ extends JCEStreamCipher
+ {
+ public Skipjack_OFB8()
+ {
+ super(new OFBBlockCipher(new SkipjackEngine(), 8), 64);
+ }
+ }
+
+ /**
+ * Blowfish
+ */
+ static public class Blowfish_OFB8
+ extends JCEStreamCipher
+ {
+ public Blowfish_OFB8()
+ {
+ super(new OFBBlockCipher(new BlowfishEngine(), 8), 64);
+ }
+ }
+
+ /**
+ * Twofish
+ */
+ static public class Twofish_OFB8
+ extends JCEStreamCipher
+ {
+ public Twofish_OFB8()
+ {
+ super(new OFBBlockCipher(new TwofishEngine(), 8), 128);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKDSAPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKDSAPrivateKey.java
new file mode 100644
index 000000000..68781681c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKDSAPrivateKey.java
@@ -0,0 +1,180 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DSAParameter;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.DSAPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JDKDSAPrivateKey
+ implements DSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ private static final long serialVersionUID = -4677259546958385734L;
+
+ BigInteger x;
+ DSAParams dsaSpec;
+
+ private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JDKDSAPrivateKey()
+ {
+ }
+
+ JDKDSAPrivateKey(
+ DSAPrivateKey key)
+ {
+ this.x = key.getX();
+ this.dsaSpec = key.getParams();
+ }
+
+ JDKDSAPrivateKey(
+ DSAPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ JDKDSAPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ DSAParameter params = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+ DERInteger derX = ASN1Integer.getInstance(info.parsePrivateKey());
+
+ this.x = derX.getValue();
+ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+ }
+
+ JDKDSAPrivateKey(
+ DSAPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DSA";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new DERInteger(getX()));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public DSAParams getParams()
+ {
+ return dsaSpec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAPrivateKey))
+ {
+ return false;
+ }
+
+ DSAPrivateKey other = (DSAPrivateKey)o;
+
+ return this.getX().equals(other.getX())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+
+ public int hashCode()
+ {
+ return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.x = (BigInteger)in.readObject();
+ this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ attrCarrier.readObject(in);
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(x);
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+
+ attrCarrier.writeObject(out);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKDSAPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKDSAPublicKey.java
new file mode 100644
index 000000000..78d1ca09d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKDSAPublicKey.java
@@ -0,0 +1,177 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DSAParameter;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.DSAPublicKeyParameters;
+
+public class JDKDSAPublicKey
+ implements DSAPublicKey
+{
+ private static final long serialVersionUID = 1752452449903495175L;
+
+ private BigInteger y;
+ private DSAParams dsaSpec;
+
+ JDKDSAPublicKey(
+ DSAPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ JDKDSAPublicKey(
+ DSAPublicKey key)
+ {
+ this.y = key.getY();
+ this.dsaSpec = key.getParams();
+ }
+
+ JDKDSAPublicKey(
+ DSAPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+
+ JDKDSAPublicKey(
+ BigInteger y,
+ DSAParameterSpec dsaSpec)
+ {
+ this.y = y;
+ this.dsaSpec = dsaSpec;
+ }
+
+ JDKDSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+
+ DERInteger derY;
+
+ try
+ {
+ derY = (DERInteger)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DSA public key");
+ }
+
+ this.y = derY.getValue();
+
+ if (isNotNull(info.getAlgorithm().getParameters()))
+ {
+ DSAParameter params = DSAParameter.getInstance(info.getAlgorithm().getParameters());
+
+ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+ }
+ }
+
+ private boolean isNotNull(ASN1Encodable parameters)
+ {
+ return parameters != null && !DERNull.INSTANCE.equals(parameters);
+ }
+
+ public String getAlgorithm()
+ {
+ return "DSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ try
+ {
+ if (dsaSpec == null)
+ {
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new DERInteger(y)).getEncoded(ASN1Encoding.DER);
+ }
+
+ return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new DERInteger(y)).getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public DSAParams getParams()
+ {
+ return dsaSpec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("DSA Public Key").append(nl);
+ buf.append(" y: ").append(this.getY().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ public int hashCode()
+ {
+ return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAPublicKey))
+ {
+ return false;
+ }
+
+ DSAPublicKey other = (DSAPublicKey)o;
+
+ return this.getY().equals(other.getY())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.y = (BigInteger)in.readObject();
+ this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(y);
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKPKCS12StoreParameter.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKPKCS12StoreParameter.java
new file mode 100644
index 000000000..93e31df34
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/JDKPKCS12StoreParameter.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jce.provider;
+
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+
+/**
+ * @deprecated use org.spongycastle.jcajce.config.PKCS12StoreParameter
+ */
+public class JDKPKCS12StoreParameter implements LoadStoreParameter
+{
+ private OutputStream outputStream;
+ private ProtectionParameter protectionParameter;
+ private boolean useDEREncoding;
+
+ public OutputStream getOutputStream()
+ {
+ return outputStream;
+ }
+
+ public ProtectionParameter getProtectionParameter()
+ {
+ return protectionParameter;
+ }
+
+ public boolean isUseDEREncoding()
+ {
+ return useDEREncoding;
+ }
+
+ public void setOutputStream(OutputStream outputStream)
+ {
+ this.outputStream = outputStream;
+ }
+
+ public void setPassword(char[] password)
+ {
+ this.protectionParameter = new KeyStore.PasswordProtection(password);
+ }
+
+ public void setProtectionParameter(ProtectionParameter protectionParameter)
+ {
+ this.protectionParameter = protectionParameter;
+ }
+
+ public void setUseDEREncoding(boolean useDEREncoding)
+ {
+ this.useDEREncoding = useDEREncoding;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/MultiCertStoreSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/MultiCertStoreSpi.java
new file mode 100644
index 000000000..05855dec1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/MultiCertStoreSpi.java
@@ -0,0 +1,85 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.jce.MultiCertStoreParameters;
+
+public class MultiCertStoreSpi
+ extends CertStoreSpi
+{
+ private MultiCertStoreParameters params;
+
+ public MultiCertStoreSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof MultiCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.MultiCertStoreSpi: parameter must be a MultiCertStoreParameters object\n" + params.toString());
+ }
+
+ this.params = (MultiCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(CertSelector certSelector)
+ throws CertStoreException
+ {
+ boolean searchAllStores = params.getSearchAllStores();
+ Iterator iter = params.getCertStores().iterator();
+ List allCerts = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST;
+
+ while (iter.hasNext())
+ {
+ CertStore store = (CertStore)iter.next();
+ Collection certs = store.getCertificates(certSelector);
+
+ if (searchAllStores)
+ {
+ allCerts.addAll(certs);
+ }
+ else if (!certs.isEmpty())
+ {
+ return certs;
+ }
+ }
+
+ return allCerts;
+ }
+
+ public Collection engineGetCRLs(CRLSelector crlSelector)
+ throws CertStoreException
+ {
+ boolean searchAllStores = params.getSearchAllStores();
+ Iterator iter = params.getCertStores().iterator();
+ List allCRLs = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST;
+
+ while (iter.hasNext())
+ {
+ CertStore store = (CertStore)iter.next();
+ Collection crls = store.getCRLs(crlSelector);
+
+ if (searchAllStores)
+ {
+ allCRLs.addAll(crls);
+ }
+ else if (!crls.isEmpty())
+ {
+ return crls;
+ }
+ }
+
+ return allCRLs;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PEMUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PEMUtil.java
new file mode 100644
index 000000000..989d2eccd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PEMUtil.java
@@ -0,0 +1,94 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.util.encoders.Base64;
+
+public class PEMUtil
+{
+ private final String _header1;
+ private final String _header2;
+ private final String _footer1;
+ private final String _footer2;
+
+ PEMUtil(
+ String type)
+ {
+ _header1 = "-----BEGIN " + type + "-----";
+ _header2 = "-----BEGIN X509 " + type + "-----";
+ _footer1 = "-----END " + type + "-----";
+ _footer2 = "-----END X509 " + type + "-----";
+ }
+
+ private String readLine(
+ InputStream in)
+ throws IOException
+ {
+ int c;
+ StringBuffer l = new StringBuffer();
+
+ do
+ {
+ while (((c = in.read()) != '\r') && c != '\n' && (c >= 0))
+ {
+ if (c == '\r')
+ {
+ continue;
+ }
+
+ l.append((char)c);
+ }
+ }
+ while (c >= 0 && l.length() == 0);
+
+ if (c < 0)
+ {
+ return null;
+ }
+
+ return l.toString();
+ }
+
+ ASN1Sequence readPEMObject(
+ InputStream in)
+ throws IOException
+ {
+ String line;
+ StringBuffer pemBuf = new StringBuffer();
+
+ while ((line = readLine(in)) != null)
+ {
+ if (line.startsWith(_header1) || line.startsWith(_header2))
+ {
+ break;
+ }
+ }
+
+ while ((line = readLine(in)) != null)
+ {
+ if (line.startsWith(_footer1) || line.startsWith(_footer2))
+ {
+ break;
+ }
+
+ pemBuf.append(line);
+ }
+
+ if (pemBuf.length() != 0)
+ {
+ ASN1Primitive o = new ASN1InputStream(Base64.decode(pemBuf.toString())).readObject();
+ if (!(o instanceof ASN1Sequence))
+ {
+ throw new IOException("malformed PEM data encountered");
+ }
+
+ return (ASN1Sequence)o;
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java
new file mode 100644
index 000000000..bf190f573
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java
@@ -0,0 +1,303 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.Principal;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertPathBuilderSpi;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathBuilderResult;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.jce.exception.ExtCertPathBuilderException;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CertStoreSelector;
+
+public class PKIXAttrCertPathBuilderSpi
+ extends CertPathBuilderSpi
+{
+
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all information to
+ * build the CertPath
+ */
+ public CertPathBuilderResult engineBuild(CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXBuilderParameters)
+ && !(params instanceof ExtendedPKIXBuilderParameters))
+ {
+ throw new InvalidAlgorithmParameterException(
+ "Parameters must be an instance of "
+ + PKIXBuilderParameters.class.getName() + " or "
+ + ExtendedPKIXBuilderParameters.class.getName()
+ + ".");
+ }
+
+ ExtendedPKIXBuilderParameters pkixParams;
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) params;
+ }
+ else
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
+ .getInstance((PKIXBuilderParameters) params);
+ }
+
+ Collection targets;
+ Iterator targetIter;
+ List certPathList = new ArrayList();
+ X509AttributeCertificate cert;
+
+ // search target certificates
+
+ Selector certSelect = pkixParams.getTargetConstraints();
+ if (!(certSelect instanceof X509AttributeCertStoreSelector))
+ {
+ throw new CertPathBuilderException(
+ "TargetConstraints must be an instance of "
+ + X509AttributeCertStoreSelector.class.getName()
+ + " for "+this.getClass().getName()+" class.");
+ }
+
+ try
+ {
+ targets = CertPathValidatorUtilities.findCertificates((X509AttributeCertStoreSelector)certSelect, pkixParams.getStores());
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathBuilderException("Error finding target attribute certificate.", e);
+ }
+
+ if (targets.isEmpty())
+ {
+ throw new CertPathBuilderException(
+ "No attribute certificate found matching targetContraints.");
+ }
+
+ CertPathBuilderResult result = null;
+
+ // check all potential target certificates
+ targetIter = targets.iterator();
+ while (targetIter.hasNext() && result == null)
+ {
+ cert = (X509AttributeCertificate) targetIter.next();
+
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ Principal[] principals = cert.getIssuer().getPrincipals();
+ Set issuers = new HashSet();
+ for (int i = 0; i < principals.length; i++)
+ {
+ try
+ {
+ if (principals[i] instanceof X500Principal)
+ {
+ selector.setSubject(((X500Principal)principals[i]).getEncoded());
+ }
+ issuers.addAll(CertPathValidatorUtilities.findCertificates(selector, pkixParams.getStores()));
+ issuers.addAll(CertPathValidatorUtilities.findCertificates(selector, pkixParams.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathBuilderException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertPathBuilderException(
+ "cannot encode X500Principal.",
+ e);
+ }
+ }
+ if (issuers.isEmpty())
+ {
+ throw new CertPathBuilderException(
+ "Public key certificate for attribute certificate cannot be found.");
+ }
+ Iterator it = issuers.iterator();
+ while (it.hasNext() && result == null)
+ {
+ result = build(cert, (X509Certificate)it.next(), pkixParams, certPathList);
+ }
+ }
+
+ if (result == null && certPathException != null)
+ {
+ throw new ExtCertPathBuilderException(
+ "Possible certificate chain could not be validated.",
+ certPathException);
+ }
+
+ if (result == null && certPathException == null)
+ {
+ throw new CertPathBuilderException(
+ "Unable to find certificate chain.");
+ }
+
+ return result;
+ }
+
+ private Exception certPathException;
+
+ private CertPathBuilderResult build(X509AttributeCertificate attrCert, X509Certificate tbvCert,
+ ExtendedPKIXBuilderParameters pkixParams, List tbvPath)
+
+ {
+ // If tbvCert is readily present in tbvPath, it indicates having run
+ // into a cycle in the
+ // PKI graph.
+ if (tbvPath.contains(tbvCert))
+ {
+ return null;
+ }
+ // step out, the certificate is not allowed to appear in a certification
+ // chain
+ if (pkixParams.getExcludedCerts().contains(tbvCert))
+ {
+ return null;
+ }
+ // test if certificate path exceeds maximum length
+ if (pkixParams.getMaxPathLength() != -1)
+ {
+ if (tbvPath.size() - 1 > pkixParams.getMaxPathLength())
+ {
+ return null;
+ }
+ }
+
+ tbvPath.add(tbvCert);
+
+ CertificateFactory cFact;
+ CertPathValidator validator;
+ CertPathBuilderResult builderResult = null;
+
+ try
+ {
+ cFact = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ validator = CertPathValidator.getInstance("RFC3281", BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(
+ "Exception creating support classes.");
+ }
+
+ try
+ {
+ // check whether the issuer of <tbvCert> is a TrustAnchor
+ if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getTrustAnchors(),
+ pkixParams.getSigProvider()) != null)
+ {
+ CertPath certPath;
+ PKIXCertPathValidatorResult result;
+ try
+ {
+ certPath = cFact.generateCertPath(tbvPath);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Certification path could not be constructed from certificate list.",
+ e);
+ }
+
+ try
+ {
+ result = (PKIXCertPathValidatorResult) validator.validate(
+ certPath, pkixParams);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Certification path could not be validated.",
+ e);
+ }
+
+ return new PKIXCertPathBuilderResult(certPath, result
+ .getTrustAnchor(), result.getPolicyTree(), result
+ .getPublicKey());
+
+ }
+ else
+ {
+ // add additional X.509 stores from locations in certificate
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromAltNames(tbvCert, pkixParams);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new AnnotatedException(
+ "No additional X.509 stores can be added from certificate locations.",
+ e);
+ }
+ Collection issuers = new HashSet();
+ // try to get the issuer certificate from one
+ // of the stores
+ try
+ {
+ issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Cannot find issuer certificate for certificate in certification path.",
+ e);
+ }
+ if (issuers.isEmpty())
+ {
+ throw new AnnotatedException(
+ "No issuer certificate for certificate in certification path found.");
+ }
+ Iterator it = issuers.iterator();
+
+ while (it.hasNext() && builderResult == null)
+ {
+ X509Certificate issuer = (X509Certificate) it.next();
+ // TODO Use CertPathValidatorUtilities.isSelfIssued(issuer)?
+ // if untrusted self signed certificate continue
+ if (issuer.getIssuerX500Principal().equals(
+ issuer.getSubjectX500Principal()))
+ {
+ continue;
+ }
+ builderResult = build(attrCert, issuer, pkixParams, tbvPath);
+ }
+ }
+ }
+ catch (AnnotatedException e)
+ {
+ certPathException = new AnnotatedException(
+ "No valid certification path could be build.", e);
+ }
+ if (builderResult == null)
+ {
+ tbvPath.remove(tbvCert);
+ }
+ return builderResult;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXAttrCertPathValidatorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXAttrCertPathValidatorSpi.java
new file mode 100644
index 000000000..91db81449
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXAttrCertPathValidatorSpi.java
@@ -0,0 +1,99 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.CertPathValidatorSpi;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Set;
+
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+
+/**
+ * CertPathValidatorSpi implementation for X.509 Attribute Certificates la RFC 3281.
+ *
+ * @see org.spongycastle.x509.ExtendedPKIXParameters
+ */
+public class PKIXAttrCertPathValidatorSpi
+ extends CertPathValidatorSpi
+{
+
+ /**
+ * Validates an attribute certificate with the given certificate path.
+ *
+ * <p>
+ * <code>params</code> must be an instance of
+ * <code>ExtendedPKIXParameters</code>.
+ * <p>
+ * The target constraints in the <code>params</code> must be an
+ * <code>X509AttributeCertStoreSelector</code> with at least the attribute
+ * certificate criterion set. Obey that also target informations may be
+ * necessary to correctly validate this attribute certificate.
+ * <p>
+ * The attribute certificate issuer must be added to the trusted attribute
+ * issuers with {@link ExtendedPKIXParameters#setTrustedACIssuers(Set)}.
+ *
+ * @param certPath The certificate path which belongs to the attribute
+ * certificate issuer public key certificate.
+ * @param params The PKIX parameters.
+ * @return A <code>PKIXCertPathValidatorResult</code> of the result of
+ * validating the <code>certPath</code>.
+ * @throws InvalidAlgorithmParameterException if <code>params</code> is
+ * inappropriate for this validator.
+ * @throws CertPathValidatorException if the verification fails.
+ */
+ public CertPathValidatorResult engineValidate(CertPath certPath,
+ CertPathParameters params) throws CertPathValidatorException,
+ InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof ExtendedPKIXParameters))
+ {
+ throw new InvalidAlgorithmParameterException(
+ "Parameters must be a "
+ + ExtendedPKIXParameters.class.getName() + " instance.");
+ }
+ ExtendedPKIXParameters pkixParams = (ExtendedPKIXParameters) params;
+
+ Selector certSelect = pkixParams.getTargetConstraints();
+ if (!(certSelect instanceof X509AttributeCertStoreSelector))
+ {
+ throw new InvalidAlgorithmParameterException(
+ "TargetConstraints must be an instance of "
+ + X509AttributeCertStoreSelector.class.getName() + " for "
+ + this.getClass().getName() + " class.");
+ }
+ X509AttributeCertificate attrCert = ((X509AttributeCertStoreSelector) certSelect)
+ .getAttributeCert();
+
+ CertPath holderCertPath = RFC3281CertPathUtilities.processAttrCert1(attrCert, pkixParams);
+ CertPathValidatorResult result = RFC3281CertPathUtilities.processAttrCert2(certPath, pkixParams);
+ X509Certificate issuerCert = (X509Certificate) certPath
+ .getCertificates().get(0);
+ RFC3281CertPathUtilities.processAttrCert3(issuerCert, pkixParams);
+ RFC3281CertPathUtilities.processAttrCert4(issuerCert, pkixParams);
+ RFC3281CertPathUtilities.processAttrCert5(attrCert, pkixParams);
+ // 6 already done in X509AttributeCertStoreSelector
+ RFC3281CertPathUtilities.processAttrCert7(attrCert, certPath, holderCertPath, pkixParams);
+ RFC3281CertPathUtilities.additionalChecks(attrCert, pkixParams);
+ Date date = null;
+ try
+ {
+ date = CertPathValidatorUtilities
+ .getValidCertDateFromValidityModel(pkixParams, null, -1);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Could not get validity date from attribute certificate.", e);
+ }
+ RFC3281CertPathUtilities.checkCRLs(attrCert, pkixParams, issuerCert, date, certPath.getCertificates());
+ return result;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCRLUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCRLUtil.java
new file mode 100644
index 000000000..db590e7bb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCRLUtil.java
@@ -0,0 +1,155 @@
+package org.spongycastle.jce.provider;
+
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.PKIXParameters;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509Store;
+
+public class PKIXCRLUtil
+{
+ public Set findCRLs(X509CRLStoreSelector crlselect, ExtendedPKIXParameters paramsPKIX, Date currentDate)
+ throws AnnotatedException
+ {
+ Set initialSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getAdditionalStores()));
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getStores()));
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+ }
+
+ Set finalSet = new HashSet();
+ Date validityDate = currentDate;
+
+ if (paramsPKIX.getDate() != null)
+ {
+ validityDate = paramsPKIX.getDate();
+ }
+
+ // based on RFC 5280 6.3.3
+ for (Iterator it = initialSet.iterator(); it.hasNext();)
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (crl.getNextUpdate().after(validityDate))
+ {
+ X509Certificate cert = crlselect.getCertificateChecking();
+
+ if (cert != null)
+ {
+ if (crl.getThisUpdate().before(cert.getNotAfter()))
+ {
+ finalSet.add(crl);
+ }
+ }
+ else
+ {
+ finalSet.add(crl);
+ }
+ }
+ }
+
+ return finalSet;
+ }
+
+ public Set findCRLs(X509CRLStoreSelector crlselect, PKIXParameters paramsPKIX)
+ throws AnnotatedException
+ {
+ Set completeSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ completeSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+ }
+
+ return completeSet;
+ }
+
+/**
+ * Return a Collection of all CRLs found in the X509Store's that are
+ * matching the crlSelect criteriums.
+ *
+ * @param crlSelect a {@link X509CRLStoreSelector} object that will be used
+ * to select the CRLs
+ * @param crlStores a List containing only
+ * {@link org.spongycastle.x509.X509Store X509Store} objects.
+ * These are used to search for CRLs
+ *
+ * @return a Collection of all found {@link java.security.cert.X509CRL X509CRL} objects. May be
+ * empty but never <code>null</code>.
+ */
+ private final Collection findCRLs(X509CRLStoreSelector crlSelect,
+ List crlStores) throws AnnotatedException
+ {
+ Set crls = new HashSet();
+ Iterator iter = crlStores.iterator();
+
+ AnnotatedException lastException = null;
+ boolean foundValidStore = false;
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store store = (X509Store)obj;
+
+ try
+ {
+ crls.addAll(store.getMatches(crlSelect));
+ foundValidStore = true;
+ }
+ catch (StoreException e)
+ {
+ lastException = new AnnotatedException(
+ "Exception searching in X.509 CRL store.", e);
+ }
+ }
+ else
+ {
+ CertStore store = (CertStore)obj;
+
+ try
+ {
+ crls.addAll(store.getCRLs(crlSelect));
+ foundValidStore = true;
+ }
+ catch (CertStoreException e)
+ {
+ lastException = new AnnotatedException(
+ "Exception searching in X.509 CRL store.", e);
+ }
+ }
+ }
+ if (!foundValidStore && lastException != null)
+ {
+ throw lastException;
+ }
+ return crls;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java
new file mode 100644
index 000000000..e060b4f02
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java
@@ -0,0 +1,261 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertPathBuilderSpi;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathBuilderResult;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.jce.exception.ExtCertPathBuilderException;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.X509CertStoreSelector;
+
+/**
+ * Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
+ *
+ * @see CertPathBuilderSpi
+ */
+public class PKIXCertPathBuilderSpi
+ extends CertPathBuilderSpi
+{
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all information to
+ * build the CertPath
+ */
+ public CertPathBuilderResult engineBuild(CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXBuilderParameters)
+ && !(params instanceof ExtendedPKIXBuilderParameters))
+ {
+ throw new InvalidAlgorithmParameterException(
+ "Parameters must be an instance of "
+ + PKIXBuilderParameters.class.getName() + " or "
+ + ExtendedPKIXBuilderParameters.class.getName() + ".");
+ }
+
+ ExtendedPKIXBuilderParameters pkixParams = null;
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) params;
+ }
+ else
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
+ .getInstance((PKIXBuilderParameters) params);
+ }
+
+ Collection targets;
+ Iterator targetIter;
+ List certPathList = new ArrayList();
+ X509Certificate cert;
+
+ // search target certificates
+
+ Selector certSelect = pkixParams.getTargetConstraints();
+ if (!(certSelect instanceof X509CertStoreSelector))
+ {
+ throw new CertPathBuilderException(
+ "TargetConstraints must be an instance of "
+ + X509CertStoreSelector.class.getName() + " for "
+ + this.getClass().getName() + " class.");
+ }
+
+ try
+ {
+ targets = CertPathValidatorUtilities.findCertificates((X509CertStoreSelector)certSelect, pkixParams.getStores());
+ targets.addAll(CertPathValidatorUtilities.findCertificates((X509CertStoreSelector)certSelect, pkixParams.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathBuilderException(
+ "Error finding target certificate.", e);
+ }
+
+ if (targets.isEmpty())
+ {
+
+ throw new CertPathBuilderException(
+ "No certificate found matching targetContraints.");
+ }
+
+ CertPathBuilderResult result = null;
+
+ // check all potential target certificates
+ targetIter = targets.iterator();
+ while (targetIter.hasNext() && result == null)
+ {
+ cert = (X509Certificate) targetIter.next();
+ result = build(cert, pkixParams, certPathList);
+ }
+
+ if (result == null && certPathException != null)
+ {
+ if (certPathException instanceof AnnotatedException)
+ {
+ throw new CertPathBuilderException(certPathException.getMessage(), certPathException.getCause());
+ }
+ throw new CertPathBuilderException(
+ "Possible certificate chain could not be validated.",
+ certPathException);
+ }
+
+ if (result == null && certPathException == null)
+ {
+ throw new CertPathBuilderException(
+ "Unable to find certificate chain.");
+ }
+
+ return result;
+ }
+
+ private Exception certPathException;
+
+ protected CertPathBuilderResult build(X509Certificate tbvCert,
+ ExtendedPKIXBuilderParameters pkixParams, List tbvPath)
+ {
+ // If tbvCert is readily present in tbvPath, it indicates having run
+ // into a cycle in the
+ // PKI graph.
+ if (tbvPath.contains(tbvCert))
+ {
+ return null;
+ }
+ // step out, the certificate is not allowed to appear in a certification
+ // chain.
+ if (pkixParams.getExcludedCerts().contains(tbvCert))
+ {
+ return null;
+ }
+ // test if certificate path exceeds maximum length
+ if (pkixParams.getMaxPathLength() != -1)
+ {
+ if (tbvPath.size() - 1 > pkixParams.getMaxPathLength())
+ {
+ return null;
+ }
+ }
+
+ tbvPath.add(tbvCert);
+
+ CertificateFactory cFact;
+ CertPathValidator validator;
+ CertPathBuilderResult builderResult = null;
+
+ try
+ {
+ cFact = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ validator = CertPathValidator.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException("Exception creating support classes.");
+ }
+
+ try
+ {
+ // check whether the issuer of <tbvCert> is a TrustAnchor
+ if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getTrustAnchors(),
+ pkixParams.getSigProvider()) != null)
+ {
+ // exception message from possibly later tried certification
+ // chains
+ CertPath certPath = null;
+ PKIXCertPathValidatorResult result = null;
+ try
+ {
+ certPath = cFact.generateCertPath(tbvPath);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Certification path could not be constructed from certificate list.",
+ e);
+ }
+
+ try
+ {
+ result = (PKIXCertPathValidatorResult) validator.validate(
+ certPath, pkixParams);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Certification path could not be validated.", e);
+ }
+
+ return new PKIXCertPathBuilderResult(certPath, result
+ .getTrustAnchor(), result.getPolicyTree(), result
+ .getPublicKey());
+
+ }
+ else
+ {
+ // add additional X.509 stores from locations in certificate
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromAltNames(
+ tbvCert, pkixParams);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new AnnotatedException(
+ "No additiontal X.509 stores can be added from certificate locations.",
+ e);
+ }
+ Collection issuers = new HashSet();
+ // try to get the issuer certificate from one
+ // of the stores
+ try
+ {
+ issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Cannot find issuer certificate for certificate in certification path.",
+ e);
+ }
+ if (issuers.isEmpty())
+ {
+ throw new AnnotatedException(
+ "No issuer certificate for certificate in certification path found.");
+ }
+ Iterator it = issuers.iterator();
+
+ while (it.hasNext() && builderResult == null)
+ {
+ X509Certificate issuer = (X509Certificate) it.next();
+ builderResult = build(issuer, pkixParams, tbvPath);
+ }
+ }
+ }
+ catch (AnnotatedException e)
+ {
+ certPathException = e;
+ }
+ if (builderResult == null)
+ {
+ tbvPath.remove(tbvCert);
+ }
+ return builderResult;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java
new file mode 100644
index 000000000..962b2c4fc
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -0,0 +1,431 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.CertPathValidatorSpi;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+
+/**
+ * CertPathValidatorSpi implementation for X.509 Certificate validation � la RFC
+ * 3280.
+ */
+public class PKIXCertPathValidatorSpi
+ extends CertPathValidatorSpi
+{
+
+ public CertPathValidatorResult engineValidate(
+ CertPath certPath,
+ CertPathParameters params)
+ throws CertPathValidatorException,
+ InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXParameters))
+ {
+ throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName()
+ + " instance.");
+ }
+
+ ExtendedPKIXParameters paramsPKIX;
+ if (params instanceof ExtendedPKIXParameters)
+ {
+ paramsPKIX = (ExtendedPKIXParameters)params;
+ }
+ else
+ {
+ paramsPKIX = ExtendedPKIXParameters.getInstance((PKIXParameters)params);
+ }
+ if (paramsPKIX.getTrustAnchors() == null)
+ {
+ throw new InvalidAlgorithmParameterException(
+ "trustAnchors is null, this is not allowed for certification path validation.");
+ }
+
+ //
+ // 6.1.1 - inputs
+ //
+
+ //
+ // (a)
+ //
+ List certs = certPath.getCertificates();
+ int n = certs.size();
+
+ if (certs.isEmpty())
+ {
+ throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0);
+ }
+
+ //
+ // (b)
+ //
+ // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
+
+ //
+ // (c)
+ //
+ Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
+
+ //
+ // (d)
+ //
+ TrustAnchor trust;
+ try
+ {
+ trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
+ paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1);
+ }
+
+ if (trust == null)
+ {
+ throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
+ }
+
+ //
+ // (e), (f), (g) are part of the paramsPKIX object.
+ //
+ Iterator certIter;
+ int index = 0;
+ int i;
+ // Certificate for each interation of the validation loop
+ // Signature information for each iteration of the validation loop
+ //
+ // 6.1.2 - setup
+ //
+
+ //
+ // (a)
+ //
+ List[] policyNodes = new ArrayList[n + 1];
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ Set policySet = new HashSet();
+
+ policySet.add(RFC3280CertPathUtilities.ANY_POLICY);
+
+ PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(),
+ RFC3280CertPathUtilities.ANY_POLICY, false);
+
+ policyNodes[0].add(validPolicyTree);
+
+ //
+ // (b) and (c)
+ //
+ PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
+
+ // (d)
+ //
+ int explicitPolicy;
+ Set acceptablePolicies = new HashSet();
+
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ //
+ // (e)
+ //
+ int inhibitAnyPolicy;
+
+ if (paramsPKIX.isAnyPolicyInhibited())
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ //
+ // (f)
+ //
+ int policyMapping;
+
+ if (paramsPKIX.isPolicyMappingInhibited())
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ //
+ // (g), (h), (i), (j)
+ //
+ PublicKey workingPublicKey;
+ X500Principal workingIssuerName;
+
+ X509Certificate sign = trust.getTrustedCert();
+ try
+ {
+ if (sign != null)
+ {
+ workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+ workingPublicKey = sign.getPublicKey();
+ }
+ else
+ {
+ workingIssuerName = new X500Principal(trust.getCAName());
+ workingPublicKey = trust.getCAPublicKey();
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
+ -1);
+ }
+
+ AlgorithmIdentifier workingAlgId = null;
+ try
+ {
+ workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
+ }
+ DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
+
+ //
+ // (k)
+ //
+ int maxPathLength = n;
+
+ //
+ // 6.1.3
+ //
+
+ if (paramsPKIX.getTargetConstraints() != null
+ && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0)))
+ {
+ throw new ExtCertPathValidatorException(
+ "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
+ }
+
+ //
+ // initialize CertPathChecker's
+ //
+ List pathCheckers = paramsPKIX.getCertPathCheckers();
+ certIter = pathCheckers.iterator();
+ while (certIter.hasNext())
+ {
+ ((PKIXCertPathChecker) certIter.next()).init(false);
+ }
+
+ X509Certificate cert = null;
+
+ for (index = certs.size() - 1; index >= 0; index--)
+ {
+ // try
+ // {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialized the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate) certs.get(index);
+ boolean verificationAlreadyPerformed = (index == certs.size() - 1);
+
+ //
+ // 6.1.3
+ //
+
+ RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
+ verificationAlreadyPerformed, workingIssuerName, sign);
+
+ RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
+
+ validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies,
+ validPolicyTree, policyNodes, inhibitAnyPolicy);
+
+ validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree);
+
+ RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy);
+
+ //
+ // 6.1.4
+ //
+
+ if (i != n)
+ {
+ if (cert != null && cert.getVersion() == 1)
+ {
+ throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
+ certPath, index);
+ }
+
+ RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
+
+ validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree,
+ policyMapping);
+
+ RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator);
+
+ // (h)
+ explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy);
+ policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping);
+ inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy);
+
+ //
+ // (i)
+ //
+ explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy);
+ policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping);
+
+ // (j)
+ inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
+
+ // (k)
+ RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
+
+ // (l)
+ maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
+
+ // (m)
+ maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength);
+
+ // (n)
+ RFC3280CertPathUtilities.prepareNextCertN(certPath, index);
+
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+
+ // these extensions are handled by the algorithm
+ criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ // (o)
+ RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers);
+
+ // set signing certificate for next round
+ sign = cert;
+
+ // (c)
+ workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+
+ // (d)
+ try
+ {
+ workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
+ }
+
+ workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+ // (f)
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ // (e)
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ }
+
+ //
+ // 6.1.5 Wrap-up procedure
+ //
+
+ explicitPolicy = RFC3280CertPathUtilities.wrapupCertA(explicitPolicy, cert);
+
+ explicitPolicy = RFC3280CertPathUtilities.wrapupCertB(certPath, index + 1, explicitPolicy);
+
+ //
+ // (c) (d) and (e) are already done
+ //
+
+ //
+ // (f)
+ //
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ // these extensions are handled by the algorithm
+ criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ RFC3280CertPathUtilities.wrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
+
+ PKIXPolicyNode intersection = RFC3280CertPathUtilities.wrapupCertG(certPath, paramsPKIX, userInitialPolicySet,
+ index + 1, policyNodes, validPolicyTree, acceptablePolicies);
+
+ if ((explicitPolicy > 0) || (intersection != null))
+ {
+ return new PKIXCertPathValidatorResult(trust, intersection, cert.getPublicKey());
+ }
+
+ throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXNameConstraintValidator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXNameConstraintValidator.java
new file mode 100644
index 000000000..ee944a8d0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXNameConstraintValidator.java
@@ -0,0 +1,1927 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralSubtree;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.Strings;
+
+public class PKIXNameConstraintValidator
+{
+ private Set excludedSubtreesDN = new HashSet();
+
+ private Set excludedSubtreesDNS = new HashSet();
+
+ private Set excludedSubtreesEmail = new HashSet();
+
+ private Set excludedSubtreesURI = new HashSet();
+
+ private Set excludedSubtreesIP = new HashSet();
+
+ private Set permittedSubtreesDN;
+
+ private Set permittedSubtreesDNS;
+
+ private Set permittedSubtreesEmail;
+
+ private Set permittedSubtreesURI;
+
+ private Set permittedSubtreesIP;
+
+ public PKIXNameConstraintValidator()
+ {
+ }
+
+ private static boolean withinDNSubtree(
+ ASN1Sequence dns,
+ ASN1Sequence subtree)
+ {
+ if (subtree.size() < 1)
+ {
+ return false;
+ }
+
+ if (subtree.size() > dns.size())
+ {
+ return false;
+ }
+
+ for (int j = subtree.size() - 1; j >= 0; j--)
+ {
+ if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void checkPermittedDN(ASN1Sequence dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ checkPermittedDN(permittedSubtreesDN, dns);
+ }
+
+ public void checkExcludedDN(ASN1Sequence dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ checkExcludedDN(excludedSubtreesDN, dns);
+ }
+
+ private void checkPermittedDN(Set permitted, ASN1Sequence dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ if (permitted.isEmpty() && dns.size() == 0)
+ {
+ return;
+ }
+ Iterator it = permitted.iterator();
+
+ while (it.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+ if (withinDNSubtree(dns, subtree))
+ {
+ return;
+ }
+ }
+
+ throw new PKIXNameConstraintValidatorException(
+ "Subject distinguished name is not from a permitted subtree");
+ }
+
+ private void checkExcludedDN(Set excluded, ASN1Sequence dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+ if (withinDNSubtree(dns, subtree))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "Subject distinguished name is from an excluded subtree");
+ }
+ }
+ }
+
+ private Set intersectDN(Set permitted, Set dns)
+ {
+ Set intersect = new HashSet();
+ for (Iterator it = dns.iterator(); it.hasNext();)
+ {
+ ASN1Sequence dn = ASN1Sequence.getInstance(((GeneralSubtree)it
+ .next()).getBase().getName().toASN1Primitive());
+ if (permitted == null)
+ {
+ if (dn != null)
+ {
+ intersect.add(dn);
+ }
+ }
+ else
+ {
+ Iterator _iter = permitted.iterator();
+ while (_iter.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)_iter.next();
+
+ if (withinDNSubtree(dn, subtree))
+ {
+ intersect.add(dn);
+ }
+ else if (withinDNSubtree(subtree, dn))
+ {
+ intersect.add(subtree);
+ }
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private Set unionDN(Set excluded, ASN1Sequence dn)
+ {
+ if (excluded.isEmpty())
+ {
+ if (dn == null)
+ {
+ return excluded;
+ }
+ excluded.add(dn);
+
+ return excluded;
+ }
+ else
+ {
+ Set intersect = new HashSet();
+
+ Iterator it = excluded.iterator();
+ while (it.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+ if (withinDNSubtree(dn, subtree))
+ {
+ intersect.add(subtree);
+ }
+ else if (withinDNSubtree(subtree, dn))
+ {
+ intersect.add(dn);
+ }
+ else
+ {
+ intersect.add(subtree);
+ intersect.add(dn);
+ }
+ }
+
+ return intersect;
+ }
+ }
+
+ private Set intersectEmail(Set permitted, Set emails)
+ {
+ Set intersect = new HashSet();
+ for (Iterator it = emails.iterator(); it.hasNext();)
+ {
+ String email = extractNameAsString(((GeneralSubtree)it.next())
+ .getBase());
+
+ if (permitted == null)
+ {
+ if (email != null)
+ {
+ intersect.add(email);
+ }
+ }
+ else
+ {
+ Iterator it2 = permitted.iterator();
+ while (it2.hasNext())
+ {
+ String _permitted = (String)it2.next();
+
+ intersectEmail(email, _permitted, intersect);
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private Set unionEmail(Set excluded, String email)
+ {
+ if (excluded.isEmpty())
+ {
+ if (email == null)
+ {
+ return excluded;
+ }
+ excluded.add(email);
+ return excluded;
+ }
+ else
+ {
+ Set union = new HashSet();
+
+ Iterator it = excluded.iterator();
+ while (it.hasNext())
+ {
+ String _excluded = (String)it.next();
+
+ unionEmail(_excluded, email, union);
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * Returns the intersection of the permitted IP ranges in
+ * <code>permitted</code> with <code>ip</code>.
+ *
+ * @param permitted A <code>Set</code> of permitted IP addresses with
+ * their subnet mask as byte arrays.
+ * @param ips The IP address with its subnet mask.
+ * @return The <code>Set</code> of permitted IP ranges intersected with
+ * <code>ip</code>.
+ */
+ private Set intersectIP(Set permitted, Set ips)
+ {
+ Set intersect = new HashSet();
+ for (Iterator it = ips.iterator(); it.hasNext();)
+ {
+ byte[] ip = ASN1OctetString.getInstance(
+ ((GeneralSubtree)it.next()).getBase().getName()).getOctets();
+ if (permitted == null)
+ {
+ if (ip != null)
+ {
+ intersect.add(ip);
+ }
+ }
+ else
+ {
+ Iterator it2 = permitted.iterator();
+ while (it2.hasNext())
+ {
+ byte[] _permitted = (byte[])it2.next();
+ intersect.addAll(intersectIPRange(_permitted, ip));
+ }
+ }
+ }
+ return intersect;
+ }
+
+ /**
+ * Returns the union of the excluded IP ranges in <code>excluded</code>
+ * with <code>ip</code>.
+ *
+ * @param excluded A <code>Set</code> of excluded IP addresses with their
+ * subnet mask as byte arrays.
+ * @param ip The IP address with its subnet mask.
+ * @return The <code>Set</code> of excluded IP ranges unified with
+ * <code>ip</code> as byte arrays.
+ */
+ private Set unionIP(Set excluded, byte[] ip)
+ {
+ if (excluded.isEmpty())
+ {
+ if (ip == null)
+ {
+ return excluded;
+ }
+ excluded.add(ip);
+
+ return excluded;
+ }
+ else
+ {
+ Set union = new HashSet();
+
+ Iterator it = excluded.iterator();
+ while (it.hasNext())
+ {
+ byte[] _excluded = (byte[])it.next();
+ union.addAll(unionIPRange(_excluded, ip));
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * Calculates the union if two IP ranges.
+ *
+ * @param ipWithSubmask1 The first IP address with its subnet mask.
+ * @param ipWithSubmask2 The second IP address with its subnet mask.
+ * @return A <code>Set</code> with the union of both addresses.
+ */
+ private Set unionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+ {
+ Set set = new HashSet();
+
+ // difficult, adding always all IPs is not wrong
+ if (Arrays.areEqual(ipWithSubmask1, ipWithSubmask2))
+ {
+ set.add(ipWithSubmask1);
+ }
+ else
+ {
+ set.add(ipWithSubmask1);
+ set.add(ipWithSubmask2);
+ }
+ return set;
+ }
+
+ /**
+ * Calculates the interesction if two IP ranges.
+ *
+ * @param ipWithSubmask1 The first IP address with its subnet mask.
+ * @param ipWithSubmask2 The second IP address with its subnet mask.
+ * @return A <code>Set</code> with the single IP address with its subnet
+ * mask as a byte array or an empty <code>Set</code>.
+ */
+ private Set intersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+ {
+ if (ipWithSubmask1.length != ipWithSubmask2.length)
+ {
+ return Collections.EMPTY_SET;
+ }
+ byte[][] temp = extractIPsAndSubnetMasks(ipWithSubmask1, ipWithSubmask2);
+ byte ip1[] = temp[0];
+ byte subnetmask1[] = temp[1];
+ byte ip2[] = temp[2];
+ byte subnetmask2[] = temp[3];
+
+ byte minMax[][] = minMaxIPs(ip1, subnetmask1, ip2, subnetmask2);
+ byte[] min;
+ byte[] max;
+ max = min(minMax[1], minMax[3]);
+ min = max(minMax[0], minMax[2]);
+
+ // minimum IP address must be bigger than max
+ if (compareTo(min, max) == 1)
+ {
+ return Collections.EMPTY_SET;
+ }
+ // OR keeps all significant bits
+ byte[] ip = or(minMax[0], minMax[2]);
+ byte[] subnetmask = or(subnetmask1, subnetmask2);
+ return Collections.singleton(ipWithSubnetMask(ip, subnetmask));
+ }
+
+ /**
+ * Concatenates the IP address with its subnet mask.
+ *
+ * @param ip The IP address.
+ * @param subnetMask Its subnet mask.
+ * @return The concatenated IP address with its subnet mask.
+ */
+ private byte[] ipWithSubnetMask(byte[] ip, byte[] subnetMask)
+ {
+ int ipLength = ip.length;
+ byte[] temp = new byte[ipLength * 2];
+ System.arraycopy(ip, 0, temp, 0, ipLength);
+ System.arraycopy(subnetMask, 0, temp, ipLength, ipLength);
+ return temp;
+ }
+
+ /**
+ * Splits the IP addresses and their subnet mask.
+ *
+ * @param ipWithSubmask1 The first IP address with the subnet mask.
+ * @param ipWithSubmask2 The second IP address with the subnet mask.
+ * @return An array with two elements. Each element contains the IP address
+ * and the subnet mask in this order.
+ */
+ private byte[][] extractIPsAndSubnetMasks(
+ byte[] ipWithSubmask1,
+ byte[] ipWithSubmask2)
+ {
+ int ipLength = ipWithSubmask1.length / 2;
+ byte ip1[] = new byte[ipLength];
+ byte subnetmask1[] = new byte[ipLength];
+ System.arraycopy(ipWithSubmask1, 0, ip1, 0, ipLength);
+ System.arraycopy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength);
+
+ byte ip2[] = new byte[ipLength];
+ byte subnetmask2[] = new byte[ipLength];
+ System.arraycopy(ipWithSubmask2, 0, ip2, 0, ipLength);
+ System.arraycopy(ipWithSubmask2, ipLength, subnetmask2, 0, ipLength);
+ return new byte[][]
+ {ip1, subnetmask1, ip2, subnetmask2};
+ }
+
+ /**
+ * Based on the two IP addresses and their subnet masks the IP range is
+ * computed for each IP address - subnet mask pair and returned as the
+ * minimum IP address and the maximum address of the range.
+ *
+ * @param ip1 The first IP address.
+ * @param subnetmask1 The subnet mask of the first IP address.
+ * @param ip2 The second IP address.
+ * @param subnetmask2 The subnet mask of the second IP address.
+ * @return A array with two elements. The first/second element contains the
+ * min and max IP address of the first/second IP address and its
+ * subnet mask.
+ */
+ private byte[][] minMaxIPs(
+ byte[] ip1,
+ byte[] subnetmask1,
+ byte[] ip2,
+ byte[] subnetmask2)
+ {
+ int ipLength = ip1.length;
+ byte[] min1 = new byte[ipLength];
+ byte[] max1 = new byte[ipLength];
+
+ byte[] min2 = new byte[ipLength];
+ byte[] max2 = new byte[ipLength];
+
+ for (int i = 0; i < ipLength; i++)
+ {
+ min1[i] = (byte)(ip1[i] & subnetmask1[i]);
+ max1[i] = (byte)(ip1[i] & subnetmask1[i] | ~subnetmask1[i]);
+
+ min2[i] = (byte)(ip2[i] & subnetmask2[i]);
+ max2[i] = (byte)(ip2[i] & subnetmask2[i] | ~subnetmask2[i]);
+ }
+
+ return new byte[][]{min1, max1, min2, max2};
+ }
+
+ private void checkPermittedEmail(Set permitted, String email)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ Iterator it = permitted.iterator();
+
+ while (it.hasNext())
+ {
+ String str = ((String)it.next());
+
+ if (emailIsConstrained(email, str))
+ {
+ return;
+ }
+ }
+
+ if (email.length() == 0 && permitted.size() == 0)
+ {
+ return;
+ }
+
+ throw new PKIXNameConstraintValidatorException(
+ "Subject email address is not from a permitted subtree.");
+ }
+
+ private void checkExcludedEmail(Set excluded, String email)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ String str = (String)it.next();
+
+ if (emailIsConstrained(email, str))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "Email address is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * Checks if the IP <code>ip</code> is included in the permitted set
+ * <code>permitted</code>.
+ *
+ * @param permitted A <code>Set</code> of permitted IP addresses with
+ * their subnet mask as byte arrays.
+ * @param ip The IP address.
+ * @throws PKIXNameConstraintValidatorException
+ * if the IP is not permitted.
+ */
+ private void checkPermittedIP(Set permitted, byte[] ip)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ Iterator it = permitted.iterator();
+
+ while (it.hasNext())
+ {
+ byte[] ipWithSubnet = (byte[])it.next();
+
+ if (isIPConstrained(ip, ipWithSubnet))
+ {
+ return;
+ }
+ }
+ if (ip.length == 0 && permitted.size() == 0)
+ {
+ return;
+ }
+ throw new PKIXNameConstraintValidatorException(
+ "IP is not from a permitted subtree.");
+ }
+
+ /**
+ * Checks if the IP <code>ip</code> is included in the excluded set
+ * <code>excluded</code>.
+ *
+ * @param excluded A <code>Set</code> of excluded IP addresses with their
+ * subnet mask as byte arrays.
+ * @param ip The IP address.
+ * @throws PKIXNameConstraintValidatorException
+ * if the IP is excluded.
+ */
+ private void checkExcludedIP(Set excluded, byte[] ip)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ byte[] ipWithSubnet = (byte[])it.next();
+
+ if (isIPConstrained(ip, ipWithSubnet))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "IP is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * Checks if the IP address <code>ip</code> is constrained by
+ * <code>constraint</code>.
+ *
+ * @param ip The IP address.
+ * @param constraint The constraint. This is an IP address concatenated with
+ * its subnetmask.
+ * @return <code>true</code> if constrained, <code>false</code>
+ * otherwise.
+ */
+ private boolean isIPConstrained(byte ip[], byte[] constraint)
+ {
+ int ipLength = ip.length;
+
+ if (ipLength != (constraint.length / 2))
+ {
+ return false;
+ }
+
+ byte[] subnetMask = new byte[ipLength];
+ System.arraycopy(constraint, ipLength, subnetMask, 0, ipLength);
+
+ byte[] permittedSubnetAddress = new byte[ipLength];
+
+ byte[] ipSubnetAddress = new byte[ipLength];
+
+ // the resulting IP address by applying the subnet mask
+ for (int i = 0; i < ipLength; i++)
+ {
+ permittedSubnetAddress[i] = (byte)(constraint[i] & subnetMask[i]);
+ ipSubnetAddress[i] = (byte)(ip[i] & subnetMask[i]);
+ }
+
+ return Arrays.areEqual(permittedSubnetAddress, ipSubnetAddress);
+ }
+
+ private boolean emailIsConstrained(String email, String constraint)
+ {
+ String sub = email.substring(email.indexOf('@') + 1);
+ // a particular mailbox
+ if (constraint.indexOf('@') != -1)
+ {
+ if (email.equalsIgnoreCase(constraint))
+ {
+ return true;
+ }
+ }
+ // on particular host
+ else if (!(constraint.charAt(0) == '.'))
+ {
+ if (sub.equalsIgnoreCase(constraint))
+ {
+ return true;
+ }
+ }
+ // address in sub domain
+ else if (withinDomain(sub, constraint))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean withinDomain(String testDomain, String domain)
+ {
+ String tempDomain = domain;
+ if (tempDomain.startsWith("."))
+ {
+ tempDomain = tempDomain.substring(1);
+ }
+ String[] domainParts = Strings.split(tempDomain, '.');
+ String[] testDomainParts = Strings.split(testDomain, '.');
+ // must have at least one subdomain
+ if (testDomainParts.length <= domainParts.length)
+ {
+ return false;
+ }
+ int d = testDomainParts.length - domainParts.length;
+ for (int i = -1; i < domainParts.length; i++)
+ {
+ if (i == -1)
+ {
+ if (testDomainParts[i + d].equals(""))
+ {
+ return false;
+ }
+ }
+ else if (!domainParts[i].equalsIgnoreCase(testDomainParts[i + d]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void checkPermittedDNS(Set permitted, String dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ Iterator it = permitted.iterator();
+
+ while (it.hasNext())
+ {
+ String str = ((String)it.next());
+
+ // is sub domain
+ if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
+ {
+ return;
+ }
+ }
+ if (dns.length() == 0 && permitted.size() == 0)
+ {
+ return;
+ }
+ throw new PKIXNameConstraintValidatorException(
+ "DNS is not from a permitted subtree.");
+ }
+
+ private void checkExcludedDNS(Set excluded, String dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ String str = ((String)it.next());
+
+ // is sub domain or the same
+ if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "DNS is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * The common part of <code>email1</code> and <code>email2</code> is
+ * added to the union <code>union</code>. If <code>email1</code> and
+ * <code>email2</code> have nothing in common they are added both.
+ *
+ * @param email1 Email address constraint 1.
+ * @param email2 Email address constraint 2.
+ * @param union The union.
+ */
+ private void unionEmail(String email1, String email2, Set union)
+ {
+ // email1 is a particular address
+ if (email1.indexOf('@') != -1)
+ {
+ String _sub = email1.substring(email1.indexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.indexOf('@') != -1)
+ {
+ if (email1.equalsIgnoreCase(email2))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(_sub, email2))
+ {
+ union.add(email2);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (_sub.equalsIgnoreCase(email2))
+ {
+ union.add(email2);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ }
+ // email1 specifies a domain
+ else if (email1.startsWith("."))
+ {
+ if (email2.indexOf('@') != -1)
+ {
+ String _sub = email2.substring(email1.indexOf('@') + 1);
+ if (withinDomain(_sub, email1))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(email1, email2)
+ || email1.equalsIgnoreCase(email2))
+ {
+ union.add(email2);
+ }
+ else if (withinDomain(email2, email1))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ else
+ {
+ if (withinDomain(email2, email1))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ }
+ // email specifies a host
+ else
+ {
+ if (email2.indexOf('@') != -1)
+ {
+ String _sub = email2.substring(email1.indexOf('@') + 1);
+ if (_sub.equalsIgnoreCase(email1))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(email1, email2))
+ {
+ union.add(email2);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (email1.equalsIgnoreCase(email2))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ }
+ }
+
+ private void unionURI(String email1, String email2, Set union)
+ {
+ // email1 is a particular address
+ if (email1.indexOf('@') != -1)
+ {
+ String _sub = email1.substring(email1.indexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.indexOf('@') != -1)
+ {
+ if (email1.equalsIgnoreCase(email2))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(_sub, email2))
+ {
+ union.add(email2);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (_sub.equalsIgnoreCase(email2))
+ {
+ union.add(email2);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ }
+ // email1 specifies a domain
+ else if (email1.startsWith("."))
+ {
+ if (email2.indexOf('@') != -1)
+ {
+ String _sub = email2.substring(email1.indexOf('@') + 1);
+ if (withinDomain(_sub, email1))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(email1, email2)
+ || email1.equalsIgnoreCase(email2))
+ {
+ union.add(email2);
+ }
+ else if (withinDomain(email2, email1))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ else
+ {
+ if (withinDomain(email2, email1))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ }
+ // email specifies a host
+ else
+ {
+ if (email2.indexOf('@') != -1)
+ {
+ String _sub = email2.substring(email1.indexOf('@') + 1);
+ if (_sub.equalsIgnoreCase(email1))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(email1, email2))
+ {
+ union.add(email2);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (email1.equalsIgnoreCase(email2))
+ {
+ union.add(email1);
+ }
+ else
+ {
+ union.add(email1);
+ union.add(email2);
+ }
+ }
+ }
+ }
+
+ private Set intersectDNS(Set permitted, Set dnss)
+ {
+ Set intersect = new HashSet();
+ for (Iterator it = dnss.iterator(); it.hasNext();)
+ {
+ String dns = extractNameAsString(((GeneralSubtree)it.next())
+ .getBase());
+ if (permitted == null)
+ {
+ if (dns != null)
+ {
+ intersect.add(dns);
+ }
+ }
+ else
+ {
+ Iterator _iter = permitted.iterator();
+ while (_iter.hasNext())
+ {
+ String _permitted = (String)_iter.next();
+
+ if (withinDomain(_permitted, dns))
+ {
+ intersect.add(_permitted);
+ }
+ else if (withinDomain(dns, _permitted))
+ {
+ intersect.add(dns);
+ }
+ }
+ }
+ }
+
+ return intersect;
+ }
+
+ protected Set unionDNS(Set excluded, String dns)
+ {
+ if (excluded.isEmpty())
+ {
+ if (dns == null)
+ {
+ return excluded;
+ }
+ excluded.add(dns);
+
+ return excluded;
+ }
+ else
+ {
+ Set union = new HashSet();
+
+ Iterator _iter = excluded.iterator();
+ while (_iter.hasNext())
+ {
+ String _permitted = (String)_iter.next();
+
+ if (withinDomain(_permitted, dns))
+ {
+ union.add(dns);
+ }
+ else if (withinDomain(dns, _permitted))
+ {
+ union.add(_permitted);
+ }
+ else
+ {
+ union.add(_permitted);
+ union.add(dns);
+ }
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * The most restricting part from <code>email1</code> and
+ * <code>email2</code> is added to the intersection <code>intersect</code>.
+ *
+ * @param email1 Email address constraint 1.
+ * @param email2 Email address constraint 2.
+ * @param intersect The intersection.
+ */
+ private void intersectEmail(String email1, String email2, Set intersect)
+ {
+ // email1 is a particular address
+ if (email1.indexOf('@') != -1)
+ {
+ String _sub = email1.substring(email1.indexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.indexOf('@') != -1)
+ {
+ if (email1.equalsIgnoreCase(email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(_sub, email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (_sub.equalsIgnoreCase(email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ }
+ // email specifies a domain
+ else if (email1.startsWith("."))
+ {
+ if (email2.indexOf('@') != -1)
+ {
+ String _sub = email2.substring(email1.indexOf('@') + 1);
+ if (withinDomain(_sub, email1))
+ {
+ intersect.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(email1, email2)
+ || email1.equalsIgnoreCase(email2))
+ {
+ intersect.add(email1);
+ }
+ else if (withinDomain(email2, email1))
+ {
+ intersect.add(email2);
+ }
+ }
+ else
+ {
+ if (withinDomain(email2, email1))
+ {
+ intersect.add(email2);
+ }
+ }
+ }
+ // email1 specifies a host
+ else
+ {
+ if (email2.indexOf('@') != -1)
+ {
+ String _sub = email2.substring(email2.indexOf('@') + 1);
+ if (_sub.equalsIgnoreCase(email1))
+ {
+ intersect.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(email1, email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (email1.equalsIgnoreCase(email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ }
+ }
+
+ private void checkExcludedURI(Set excluded, String uri)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ String str = ((String)it.next());
+
+ if (isUriConstrained(uri, str))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "URI is from an excluded subtree.");
+ }
+ }
+ }
+
+ private Set intersectURI(Set permitted, Set uris)
+ {
+ Set intersect = new HashSet();
+ for (Iterator it = uris.iterator(); it.hasNext();)
+ {
+ String uri = extractNameAsString(((GeneralSubtree)it.next())
+ .getBase());
+ if (permitted == null)
+ {
+ if (uri != null)
+ {
+ intersect.add(uri);
+ }
+ }
+ else
+ {
+ Iterator _iter = permitted.iterator();
+ while (_iter.hasNext())
+ {
+ String _permitted = (String)_iter.next();
+ intersectURI(_permitted, uri, intersect);
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private Set unionURI(Set excluded, String uri)
+ {
+ if (excluded.isEmpty())
+ {
+ if (uri == null)
+ {
+ return excluded;
+ }
+ excluded.add(uri);
+
+ return excluded;
+ }
+ else
+ {
+ Set union = new HashSet();
+
+ Iterator _iter = excluded.iterator();
+ while (_iter.hasNext())
+ {
+ String _excluded = (String)_iter.next();
+
+ unionURI(_excluded, uri, union);
+ }
+
+ return union;
+ }
+ }
+
+ private void intersectURI(String email1, String email2, Set intersect)
+ {
+ // email1 is a particular address
+ if (email1.indexOf('@') != -1)
+ {
+ String _sub = email1.substring(email1.indexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.indexOf('@') != -1)
+ {
+ if (email1.equalsIgnoreCase(email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(_sub, email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (_sub.equalsIgnoreCase(email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ }
+ // email specifies a domain
+ else if (email1.startsWith("."))
+ {
+ if (email2.indexOf('@') != -1)
+ {
+ String _sub = email2.substring(email1.indexOf('@') + 1);
+ if (withinDomain(_sub, email1))
+ {
+ intersect.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(email1, email2)
+ || email1.equalsIgnoreCase(email2))
+ {
+ intersect.add(email1);
+ }
+ else if (withinDomain(email2, email1))
+ {
+ intersect.add(email2);
+ }
+ }
+ else
+ {
+ if (withinDomain(email2, email1))
+ {
+ intersect.add(email2);
+ }
+ }
+ }
+ // email1 specifies a host
+ else
+ {
+ if (email2.indexOf('@') != -1)
+ {
+ String _sub = email2.substring(email2.indexOf('@') + 1);
+ if (_sub.equalsIgnoreCase(email1))
+ {
+ intersect.add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (email2.startsWith("."))
+ {
+ if (withinDomain(email1, email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (email1.equalsIgnoreCase(email2))
+ {
+ intersect.add(email1);
+ }
+ }
+ }
+ }
+
+ private void checkPermittedURI(Set permitted, String uri)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ Iterator it = permitted.iterator();
+
+ while (it.hasNext())
+ {
+ String str = ((String)it.next());
+
+ if (isUriConstrained(uri, str))
+ {
+ return;
+ }
+ }
+ if (uri.length() == 0 && permitted.size() == 0)
+ {
+ return;
+ }
+ throw new PKIXNameConstraintValidatorException(
+ "URI is not from a permitted subtree.");
+ }
+
+ private boolean isUriConstrained(String uri, String constraint)
+ {
+ String host = extractHostFromURL(uri);
+ // a host
+ if (!constraint.startsWith("."))
+ {
+ if (host.equalsIgnoreCase(constraint))
+ {
+ return true;
+ }
+ }
+
+ // in sub domain or domain
+ else if (withinDomain(host, constraint))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static String extractHostFromURL(String url)
+ {
+ // see RFC 1738
+ // remove ':' after protocol, e.g. http:
+ String sub = url.substring(url.indexOf(':') + 1);
+ // extract host from Common Internet Scheme Syntax, e.g. http://
+ if (sub.indexOf("//") != -1)
+ {
+ sub = sub.substring(sub.indexOf("//") + 2);
+ }
+ // first remove port, e.g. http://test.com:21
+ if (sub.lastIndexOf(':') != -1)
+ {
+ sub = sub.substring(0, sub.lastIndexOf(':'));
+ }
+ // remove user and password, e.g. http://john:password@test.com
+ sub = sub.substring(sub.indexOf(':') + 1);
+ sub = sub.substring(sub.indexOf('@') + 1);
+ // remove local parts, e.g. http://test.com/bla
+ if (sub.indexOf('/') != -1)
+ {
+ sub = sub.substring(0, sub.indexOf('/'));
+ }
+ return sub;
+ }
+
+ /**
+ * Checks if the given GeneralName is in the permitted set.
+ *
+ * @param name The GeneralName
+ * @throws PKIXNameConstraintValidatorException
+ * If the <code>name</code>
+ */
+ public void checkPermitted(GeneralName name)
+ throws PKIXNameConstraintValidatorException
+ {
+ switch (name.getTagNo())
+ {
+ case 1:
+ checkPermittedEmail(permittedSubtreesEmail,
+ extractNameAsString(name));
+ break;
+ case 2:
+ checkPermittedDNS(permittedSubtreesDNS, DERIA5String.getInstance(
+ name.getName()).getString());
+ break;
+ case 4:
+ checkPermittedDN(ASN1Sequence.getInstance(name.getName()
+ .toASN1Primitive()));
+ break;
+ case 6:
+ checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance(
+ name.getName()).getString());
+ break;
+ case 7:
+ byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+ checkPermittedIP(permittedSubtreesIP, ip);
+ }
+ }
+
+ /**
+ * Check if the given GeneralName is contained in the excluded set.
+ *
+ * @param name The GeneralName.
+ * @throws PKIXNameConstraintValidatorException
+ * If the <code>name</code> is
+ * excluded.
+ */
+ public void checkExcluded(GeneralName name)
+ throws PKIXNameConstraintValidatorException
+ {
+ switch (name.getTagNo())
+ {
+ case 1:
+ checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name));
+ break;
+ case 2:
+ checkExcludedDNS(excludedSubtreesDNS, DERIA5String.getInstance(
+ name.getName()).getString());
+ break;
+ case 4:
+ checkExcludedDN(ASN1Sequence.getInstance(name.getName()
+ .toASN1Primitive()));
+ break;
+ case 6:
+ checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance(
+ name.getName()).getString());
+ break;
+ case 7:
+ byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+ checkExcludedIP(excludedSubtreesIP, ip);
+ }
+ }
+
+ public void intersectPermittedSubtree(GeneralSubtree permitted)
+ {
+ intersectPermittedSubtree(new GeneralSubtree[] { permitted });
+ }
+
+ /**
+ * Updates the permitted set of these name constraints with the intersection
+ * with the given subtree.
+ *
+ * @param permitted The permitted subtrees
+ */
+
+ public void intersectPermittedSubtree(GeneralSubtree[] permitted)
+ {
+ Map subtreesMap = new HashMap();
+
+ // group in sets in a map ordered by tag no.
+ for (int i = 0; i != permitted.length; i++)
+ {
+ GeneralSubtree subtree = permitted[i];
+ Integer tagNo = Integers.valueOf(subtree.getBase().getTagNo());
+ if (subtreesMap.get(tagNo) == null)
+ {
+ subtreesMap.put(tagNo, new HashSet());
+ }
+ ((Set)subtreesMap.get(tagNo)).add(subtree);
+ }
+
+ for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext();)
+ {
+ Map.Entry entry = (Map.Entry)it.next();
+
+ // go through all subtree groups
+ switch (((Integer)entry.getKey()).intValue())
+ {
+ case 1:
+ permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail,
+ (Set)entry.getValue());
+ break;
+ case 2:
+ permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
+ (Set)entry.getValue());
+ break;
+ case 4:
+ permittedSubtreesDN = intersectDN(permittedSubtreesDN,
+ (Set)entry.getValue());
+ break;
+ case 6:
+ permittedSubtreesURI = intersectURI(permittedSubtreesURI,
+ (Set)entry.getValue());
+ break;
+ case 7:
+ permittedSubtreesIP = intersectIP(permittedSubtreesIP,
+ (Set)entry.getValue());
+ }
+ }
+ }
+
+ private String extractNameAsString(GeneralName name)
+ {
+ return DERIA5String.getInstance(name.getName()).getString();
+ }
+
+ public void intersectEmptyPermittedSubtree(int nameType)
+ {
+ switch (nameType)
+ {
+ case 1:
+ permittedSubtreesEmail = new HashSet();
+ break;
+ case 2:
+ permittedSubtreesDNS = new HashSet();
+ break;
+ case 4:
+ permittedSubtreesDN = new HashSet();
+ break;
+ case 6:
+ permittedSubtreesURI = new HashSet();
+ break;
+ case 7:
+ permittedSubtreesIP = new HashSet();
+ }
+ }
+
+ /**
+ * Adds a subtree to the excluded set of these name constraints.
+ *
+ * @param subtree A subtree with an excluded GeneralName.
+ */
+ public void addExcludedSubtree(GeneralSubtree subtree)
+ {
+ GeneralName base = subtree.getBase();
+
+ switch (base.getTagNo())
+ {
+ case 1:
+ excludedSubtreesEmail = unionEmail(excludedSubtreesEmail,
+ extractNameAsString(base));
+ break;
+ case 2:
+ excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
+ extractNameAsString(base));
+ break;
+ case 4:
+ excludedSubtreesDN = unionDN(excludedSubtreesDN,
+ (ASN1Sequence)base.getName().toASN1Primitive());
+ break;
+ case 6:
+ excludedSubtreesURI = unionURI(excludedSubtreesURI,
+ extractNameAsString(base));
+ break;
+ case 7:
+ excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString
+ .getInstance(base.getName()).getOctets());
+ break;
+ }
+ }
+
+ /**
+ * Returns the maximum IP address.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The maximum IP address.
+ */
+ private static byte[] max(byte[] ip1, byte[] ip2)
+ {
+ for (int i = 0; i < ip1.length; i++)
+ {
+ if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF))
+ {
+ return ip1;
+ }
+ }
+ return ip2;
+ }
+
+ /**
+ * Returns the minimum IP address.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The minimum IP address.
+ */
+ private static byte[] min(byte[] ip1, byte[] ip2)
+ {
+ for (int i = 0; i < ip1.length; i++)
+ {
+ if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF))
+ {
+ return ip1;
+ }
+ }
+ return ip2;
+ }
+
+ /**
+ * Compares IP address <code>ip1</code> with <code>ip2</code>. If ip1
+ * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1
+ * otherwise.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise.
+ */
+ private static int compareTo(byte[] ip1, byte[] ip2)
+ {
+ if (Arrays.areEqual(ip1, ip2))
+ {
+ return 0;
+ }
+ if (Arrays.areEqual(max(ip1, ip2), ip1))
+ {
+ return 1;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the logical OR of the IP addresses <code>ip1</code> and
+ * <code>ip2</code>.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The OR of <code>ip1</code> and <code>ip2</code>.
+ */
+ private static byte[] or(byte[] ip1, byte[] ip2)
+ {
+ byte[] temp = new byte[ip1.length];
+ for (int i = 0; i < ip1.length; i++)
+ {
+ temp[i] = (byte)(ip1[i] | ip2[i]);
+ }
+ return temp;
+ }
+
+ public int hashCode()
+ {
+ return hashCollection(excludedSubtreesDN)
+ + hashCollection(excludedSubtreesDNS)
+ + hashCollection(excludedSubtreesEmail)
+ + hashCollection(excludedSubtreesIP)
+ + hashCollection(excludedSubtreesURI)
+ + hashCollection(permittedSubtreesDN)
+ + hashCollection(permittedSubtreesDNS)
+ + hashCollection(permittedSubtreesEmail)
+ + hashCollection(permittedSubtreesIP)
+ + hashCollection(permittedSubtreesURI);
+ }
+
+ private int hashCollection(Collection coll)
+ {
+ if (coll == null)
+ {
+ return 0;
+ }
+ int hash = 0;
+ Iterator it1 = coll.iterator();
+ while (it1.hasNext())
+ {
+ Object o = it1.next();
+ if (o instanceof byte[])
+ {
+ hash += Arrays.hashCode((byte[])o);
+ }
+ else
+ {
+ hash += o.hashCode();
+ }
+ }
+ return hash;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof PKIXNameConstraintValidator))
+ {
+ return false;
+ }
+ PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o;
+ return collectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN)
+ && collectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS)
+ && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail)
+ && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP)
+ && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI)
+ && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN)
+ && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS)
+ && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail)
+ && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP)
+ && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI);
+ }
+
+ private boolean collectionsAreEqual(Collection coll1, Collection coll2)
+ {
+ if (coll1 == coll2)
+ {
+ return true;
+ }
+ if (coll1 == null || coll2 == null)
+ {
+ return false;
+ }
+ if (coll1.size() != coll2.size())
+ {
+ return false;
+ }
+ Iterator it1 = coll1.iterator();
+
+ while (it1.hasNext())
+ {
+ Object a = it1.next();
+ Iterator it2 = coll2.iterator();
+ boolean found = false;
+ while (it2.hasNext())
+ {
+ Object b = it2.next();
+ if (equals(a, b))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean equals(Object o1, Object o2)
+ {
+ if (o1 == o2)
+ {
+ return true;
+ }
+ if (o1 == null || o2 == null)
+ {
+ return false;
+ }
+ if (o1 instanceof byte[] && o2 instanceof byte[])
+ {
+ return Arrays.areEqual((byte[])o1, (byte[])o2);
+ }
+ else
+ {
+ return o1.equals(o2);
+ }
+ }
+
+ /**
+ * Stringifies an IPv4 or v6 address with subnet mask.
+ *
+ * @param ip The IP with subnet mask.
+ * @return The stringified IP address.
+ */
+ private String stringifyIP(byte[] ip)
+ {
+ String temp = "";
+ for (int i = 0; i < ip.length / 2; i++)
+ {
+ temp += Integer.toString(ip[i] & 0x00FF) + ".";
+ }
+ temp = temp.substring(0, temp.length() - 1);
+ temp += "/";
+ for (int i = ip.length / 2; i < ip.length; i++)
+ {
+ temp += Integer.toString(ip[i] & 0x00FF) + ".";
+ }
+ temp = temp.substring(0, temp.length() - 1);
+ return temp;
+ }
+
+ private String stringifyIPCollection(Set ips)
+ {
+ String temp = "";
+ temp += "[";
+ for (Iterator it = ips.iterator(); it.hasNext();)
+ {
+ temp += stringifyIP((byte[])it.next()) + ",";
+ }
+ if (temp.length() > 1)
+ {
+ temp = temp.substring(0, temp.length() - 1);
+ }
+ temp += "]";
+ return temp;
+ }
+
+ public String toString()
+ {
+ String temp = "";
+ temp += "permitted:\n";
+ if (permittedSubtreesDN != null)
+ {
+ temp += "DN:\n";
+ temp += permittedSubtreesDN.toString() + "\n";
+ }
+ if (permittedSubtreesDNS != null)
+ {
+ temp += "DNS:\n";
+ temp += permittedSubtreesDNS.toString() + "\n";
+ }
+ if (permittedSubtreesEmail != null)
+ {
+ temp += "Email:\n";
+ temp += permittedSubtreesEmail.toString() + "\n";
+ }
+ if (permittedSubtreesURI != null)
+ {
+ temp += "URI:\n";
+ temp += permittedSubtreesURI.toString() + "\n";
+ }
+ if (permittedSubtreesIP != null)
+ {
+ temp += "IP:\n";
+ temp += stringifyIPCollection(permittedSubtreesIP) + "\n";
+ }
+ temp += "excluded:\n";
+ if (!excludedSubtreesDN.isEmpty())
+ {
+ temp += "DN:\n";
+ temp += excludedSubtreesDN.toString() + "\n";
+ }
+ if (!excludedSubtreesDNS.isEmpty())
+ {
+ temp += "DNS:\n";
+ temp += excludedSubtreesDNS.toString() + "\n";
+ }
+ if (!excludedSubtreesEmail.isEmpty())
+ {
+ temp += "Email:\n";
+ temp += excludedSubtreesEmail.toString() + "\n";
+ }
+ if (!excludedSubtreesURI.isEmpty())
+ {
+ temp += "URI:\n";
+ temp += excludedSubtreesURI.toString() + "\n";
+ }
+ if (!excludedSubtreesIP.isEmpty())
+ {
+ temp += "IP:\n";
+ temp += stringifyIPCollection(excludedSubtreesIP) + "\n";
+ }
+ return temp;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXNameConstraintValidatorException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXNameConstraintValidatorException.java
new file mode 100644
index 000000000..3f4bef58b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXNameConstraintValidatorException.java
@@ -0,0 +1,10 @@
+package org.spongycastle.jce.provider;
+
+public class PKIXNameConstraintValidatorException
+ extends Exception
+{
+ public PKIXNameConstraintValidatorException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXPolicyNode.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXPolicyNode.java
new file mode 100644
index 000000000..10b15b333
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/PKIXPolicyNode.java
@@ -0,0 +1,168 @@
+package org.spongycastle.jce.provider;
+
+import java.security.cert.PolicyNode;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+public class PKIXPolicyNode
+ implements PolicyNode
+{
+ protected List children;
+ protected int depth;
+ protected Set expectedPolicies;
+ protected PolicyNode parent;
+ protected Set policyQualifiers;
+ protected String validPolicy;
+ protected boolean critical;
+
+ /*
+ *
+ * CONSTRUCTORS
+ *
+ */
+
+ public PKIXPolicyNode(
+ List _children,
+ int _depth,
+ Set _expectedPolicies,
+ PolicyNode _parent,
+ Set _policyQualifiers,
+ String _validPolicy,
+ boolean _critical)
+ {
+ children = _children;
+ depth = _depth;
+ expectedPolicies = _expectedPolicies;
+ parent = _parent;
+ policyQualifiers = _policyQualifiers;
+ validPolicy = _validPolicy;
+ critical = _critical;
+ }
+
+ public void addChild(
+ PKIXPolicyNode _child)
+ {
+ children.add(_child);
+ _child.setParent(this);
+ }
+
+ public Iterator getChildren()
+ {
+ return children.iterator();
+ }
+
+ public int getDepth()
+ {
+ return depth;
+ }
+
+ public Set getExpectedPolicies()
+ {
+ return expectedPolicies;
+ }
+
+ public PolicyNode getParent()
+ {
+ return parent;
+ }
+
+ public Set getPolicyQualifiers()
+ {
+ return policyQualifiers;
+ }
+
+ public String getValidPolicy()
+ {
+ return validPolicy;
+ }
+
+ public boolean hasChildren()
+ {
+ return !children.isEmpty();
+ }
+
+ public boolean isCritical()
+ {
+ return critical;
+ }
+
+ public void removeChild(PKIXPolicyNode _child)
+ {
+ children.remove(_child);
+ }
+
+ public void setCritical(boolean _critical)
+ {
+ critical = _critical;
+ }
+
+ public void setParent(PKIXPolicyNode _parent)
+ {
+ parent = _parent;
+ }
+
+ public String toString()
+ {
+ return toString("");
+ }
+
+ public String toString(String _indent)
+ {
+ StringBuffer _buf = new StringBuffer();
+ _buf.append(_indent);
+ _buf.append(validPolicy);
+ _buf.append(" {\n");
+
+ for(int i = 0; i < children.size(); i++)
+ {
+ _buf.append(((PKIXPolicyNode)children.get(i)).toString(_indent + " "));
+ }
+
+ _buf.append(_indent);
+ _buf.append("}\n");
+ return _buf.toString();
+ }
+
+ public Object clone()
+ {
+ return copy();
+ }
+
+ public PKIXPolicyNode copy()
+ {
+ Set _expectedPolicies = new HashSet();
+ Iterator _iter = expectedPolicies.iterator();
+ while (_iter.hasNext())
+ {
+ _expectedPolicies.add(new String((String)_iter.next()));
+ }
+
+ Set _policyQualifiers = new HashSet();
+ _iter = policyQualifiers.iterator();
+ while (_iter.hasNext())
+ {
+ _policyQualifiers.add(new String((String)_iter.next()));
+ }
+
+ PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(),
+ depth,
+ _expectedPolicies,
+ null,
+ _policyQualifiers,
+ new String(validPolicy),
+ critical);
+
+ _iter = children.iterator();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy();
+ _child.setParent(_node);
+ _node.addChild(_child);
+ }
+
+ return _node;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java
new file mode 100644
index 000000000..8e00d3af6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -0,0 +1,2569 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509Extension;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.GeneralSubtree;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.NameConstraints;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+
+public class RFC3280CertPathUtilities
+{
+ private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ /**
+ * If the complete CRL includes an issuing distribution point (IDP) CRL
+ * extension check the following:
+ * <p/>
+ * (i) If the distribution point name is present in the IDP CRL extension
+ * and the distribution field is present in the DP, then verify that one of
+ * the names in the IDP matches one of the names in the DP. If the
+ * distribution point name is present in the IDP CRL extension and the
+ * distribution field is omitted from the DP, then verify that one of the
+ * names in the IDP matches one of the names in the cRLIssuer field of the
+ * DP.
+ * </p>
+ * <p/>
+ * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate does not include the basic
+ * constraints extension with the cA boolean asserted.
+ * </p>
+ * <p/>
+ * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate includes the basic constraints
+ * extension with the cA boolean asserted.
+ * </p>
+ * <p/>
+ * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+ * </p>
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate.
+ * @param crl The CRL.
+ * @throws AnnotatedException if one of the conditions is not met or an error occurs.
+ */
+ protected static void processCRLB2(
+ DistributionPoint dp,
+ Object cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+ // (b) (2) (i)
+ // distribution point name is present
+ if (idp != null)
+ {
+ if (idp.getDistributionPoint() != null)
+ {
+ // make list of names
+ DistributionPointName dpName = IssuingDistributionPoint.getInstance(idp).getDistributionPoint();
+ List names = new ArrayList();
+
+ if (dpName.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ names.add(genNames[j]);
+ }
+ }
+ if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ try
+ {
+ Enumeration e = ASN1Sequence.getInstance(
+ ASN1Sequence.fromByteArray(CertPathValidatorUtilities.getIssuerPrincipal(crl)
+ .getEncoded())).getObjects();
+ while (e.hasMoreElements())
+ {
+ vec.add((ASN1Encodable)e.nextElement());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Could not read CRL issuer.", e);
+ }
+ vec.add(dpName.getName());
+ names.add(new GeneralName(X509Name.getInstance(new DERSequence(vec))));
+ }
+ boolean matches = false;
+ // verify that one of the names in the IDP matches one
+ // of the names in the DP.
+ if (dp.getDistributionPoint() != null)
+ {
+ dpName = dp.getDistributionPoint();
+ GeneralName[] genNames = null;
+ if (dpName.getType() == DistributionPointName.FULL_NAME)
+ {
+ genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+ }
+ if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ {
+ if (dp.getCRLIssuer() != null)
+ {
+ genNames = dp.getCRLIssuer().getNames();
+ }
+ else
+ {
+ genNames = new GeneralName[1];
+ try
+ {
+ genNames[0] = new GeneralName(new X509Name(
+ (ASN1Sequence)ASN1Sequence.fromByteArray(CertPathValidatorUtilities
+ .getEncodedIssuerPrincipal(cert).getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Could not read certificate issuer.", e);
+ }
+ }
+ for (int j = 0; j < genNames.length; j++)
+ {
+ Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().toASN1Primitive()).getObjects();
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ while (e.hasMoreElements())
+ {
+ vec.add((ASN1Encodable)e.nextElement());
+ }
+ vec.add(dpName.getName());
+ genNames[j] = new GeneralName(new X509Name(new DERSequence(vec)));
+ }
+ }
+ if (genNames != null)
+ {
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (names.contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ }
+ if (!matches)
+ {
+ throw new AnnotatedException(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ // verify that one of the names in
+ // the IDP matches one of the names in the cRLIssuer field of
+ // the DP
+ else
+ {
+ if (dp.getCRLIssuer() == null)
+ {
+ throw new AnnotatedException("Either the cRLIssuer or the distributionPoint field must "
+ + "be contained in DistributionPoint.");
+ }
+ GeneralName[] genNames = dp.getCRLIssuer().getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (names.contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ if (!matches)
+ {
+ throw new AnnotatedException(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ }
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue((X509Extension)cert,
+ BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Basic constraints extension could not be decoded.", e);
+ }
+
+ if (cert instanceof X509Certificate)
+ {
+ // (b) (2) (ii)
+ if (idp.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+ {
+ throw new AnnotatedException("CA Cert CRL only contains user certificates.");
+ }
+
+ // (b) (2) (iii)
+ if (idp.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+ {
+ throw new AnnotatedException("End CRL only contains CA certificates.");
+ }
+ }
+
+ // (b) (2) (iv)
+ if (idp.onlyContainsAttributeCerts())
+ {
+ throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted.");
+ }
+ }
+ }
+
+ /**
+ * If the DP includes cRLIssuer, then verify that the issuer field in the
+ * complete CRL matches cRLIssuer in the DP and that the complete CRL
+ * contains an issuing distribution point extension with the indirectCRL
+ * boolean asserted. Otherwise, verify that the CRL issuer matches the
+ * certificate issuer.
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate ot attribute certificate.
+ * @param crl The CRL for <code>cert</code>.
+ * @throws AnnotatedException if one of the above conditions does not apply or an error
+ * occurs.
+ */
+ protected static void processCRLB1(
+ DistributionPoint dp,
+ Object cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ ASN1Primitive idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+ boolean isIndirect = false;
+ if (idp != null)
+ {
+ if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL())
+ {
+ isIndirect = true;
+ }
+ }
+ byte[] issuerBytes = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded();
+
+ boolean matchIssuer = false;
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (Arrays.areEqual(genNames[j].getName().toASN1Primitive().getEncoded(), issuerBytes))
+ {
+ matchIssuer = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.", e);
+ }
+ }
+ }
+ if (matchIssuer && !isIndirect)
+ {
+ throw new AnnotatedException("Distribution point contains cRLIssuer field but CRL is not indirect.");
+ }
+ if (!matchIssuer)
+ {
+ throw new AnnotatedException("CRL issuer of CRL does not match CRL issuer of distribution point.");
+ }
+ }
+ else
+ {
+ if (CertPathValidatorUtilities.getIssuerPrincipal(crl).equals(
+ CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)))
+ {
+ matchIssuer = true;
+ }
+ }
+ if (!matchIssuer)
+ {
+ throw new AnnotatedException("Cannot find matching CRL issuer for certificate.");
+ }
+ }
+
+ protected static ReasonsMask processCRLD(
+ X509CRL crl,
+ DistributionPoint dp)
+ throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+ // (d) (1)
+ if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null)
+ {
+ return new ReasonsMask(dp.getReasons()).intersect(new ReasonsMask(idp.getOnlySomeReasons()));
+ }
+ // (d) (4)
+ if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null)
+ {
+ return ReasonsMask.allReasons;
+ }
+ // (d) (2) and (d)(3)
+ return (dp.getReasons() == null
+ ? ReasonsMask.allReasons
+ : new ReasonsMask(dp.getReasons())).intersect(idp == null
+ ? ReasonsMask.allReasons
+ : new ReasonsMask(idp.getOnlySomeReasons()));
+
+ }
+
+ public static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+
+ public static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+
+ public static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+
+ public static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+
+ public static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+
+ public static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+
+ public static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+
+ public static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+
+ public static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+
+ public static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+
+ public static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+
+ public static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ public static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+
+ public static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ public static final String ANY_POLICY = "2.5.29.32.0";
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+
+ protected static final int CRL_SIGN = 6;
+
+ /**
+ * Obtain and validate the certification path for the complete CRL issuer.
+ * If a key usage extension is present in the CRL issuer's certificate,
+ * verify that the cRLSign bit is set.
+ *
+ * @param crl CRL which contains revocation information for the certificate
+ * <code>cert</code>.
+ * @param cert The attribute certificate or certificate to check if it is
+ * revoked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param paramsPKIX paramsPKIX PKIX parameters.
+ * @param certPathCerts The certificates on the certification path.
+ * @return A <code>Set</code> with all keys of possible CRL issuer
+ * certificates.
+ * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+ * some error occurs.
+ */
+ protected static Set processCRLF(
+ X509CRL crl,
+ Object cert,
+ X509Certificate defaultCRLSignCert,
+ PublicKey defaultCRLSignKey,
+ ExtendedPKIXParameters paramsPKIX,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ // (f)
+
+ // get issuer from CRL
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ try
+ {
+ byte[] issuerPrincipal = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded();
+ selector.setSubject(issuerPrincipal);
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e);
+ }
+
+ // get CRL signing certs
+ Collection coll;
+ try
+ {
+ coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getStores());
+ coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getAdditionalStores()));
+ coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate for CRL cannot be searched.", e);
+ }
+
+ coll.add(defaultCRLSignCert);
+
+ Iterator cert_it = coll.iterator();
+
+ List validCerts = new ArrayList();
+ List validKeys = new ArrayList();
+
+ while (cert_it.hasNext())
+ {
+ X509Certificate signingCert = (X509Certificate)cert_it.next();
+
+ /*
+ * CA of the certificate, for which this CRL is checked, has also
+ * signed CRL, so skip the path validation, because is already done
+ */
+ if (signingCert.equals(defaultCRLSignCert))
+ {
+ validCerts.add(signingCert);
+ validKeys.add(defaultCRLSignKey);
+ continue;
+ }
+ try
+ {
+ CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ selector = new X509CertStoreSelector();
+ selector.setCertificate(signingCert);
+ ExtendedPKIXParameters temp = (ExtendedPKIXParameters)paramsPKIX.clone();
+ temp.setTargetCertConstraints(selector);
+ ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters)ExtendedPKIXBuilderParameters
+ .getInstance(temp);
+ /*
+ * if signingCert is placed not higher on the cert path a
+ * dependency loop results. CRL for cert is checked, but
+ * signingCert is needed for checking the CRL which is dependent
+ * on checking cert because it is higher in the cert path and so
+ * signing signingCert transitively. so, revocation is disabled,
+ * forgery attacks of the CRL are detected in this outer loop
+ * for all other it must be enabled to prevent forgery attacks
+ */
+ if (certPathCerts.contains(signingCert))
+ {
+ params.setRevocationEnabled(false);
+ }
+ else
+ {
+ params.setRevocationEnabled(true);
+ }
+ List certs = builder.build(params).getCertPath().getCertificates();
+ validCerts.add(signingCert);
+ validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0));
+ }
+ catch (CertPathBuilderException e)
+ {
+ throw new AnnotatedException("Internal error.", e);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new AnnotatedException("Public key of issuer certificate of CRL could not be retrieved.", e);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ Set checkKeys = new HashSet();
+
+ AnnotatedException lastException = null;
+ for (int i = 0; i < validCerts.size(); i++)
+ {
+ X509Certificate signCert = (X509Certificate)validCerts.get(i);
+ boolean[] keyusage = signCert.getKeyUsage();
+
+ if (keyusage != null && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+ {
+ lastException = new AnnotatedException(
+ "Issuer certificate key usage extension does not permit CRL signing.");
+ }
+ else
+ {
+ checkKeys.add(validKeys.get(i));
+ }
+ }
+
+ if (checkKeys.isEmpty() && lastException == null)
+ {
+ throw new AnnotatedException("Cannot find a valid issuer certificate.");
+ }
+ if (checkKeys.isEmpty() && lastException != null)
+ {
+ throw lastException;
+ }
+
+ return checkKeys;
+ }
+
+ protected static PublicKey processCRLG(
+ X509CRL crl,
+ Set keys)
+ throws AnnotatedException
+ {
+ Exception lastException = null;
+ for (Iterator it = keys.iterator(); it.hasNext();)
+ {
+ PublicKey key = (PublicKey)it.next();
+ try
+ {
+ crl.verify(key);
+ return key;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ throw new AnnotatedException("Cannot verify CRL.", lastException);
+ }
+
+ protected static X509CRL processCRLH(
+ Set deltacrls,
+ PublicKey key)
+ throws AnnotatedException
+ {
+ Exception lastException = null;
+
+ for (Iterator it = deltacrls.iterator(); it.hasNext();)
+ {
+ X509CRL crl = (X509CRL)it.next();
+ try
+ {
+ crl.verify(key);
+ return crl;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (lastException != null)
+ {
+ throw new AnnotatedException("Cannot verify delta CRL.", lastException);
+ }
+ return null;
+ }
+
+ protected static Set processCRLA1i(
+ Date currentDate,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ Set set = new HashSet();
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ CRLDistPoint freshestCRL = null;
+ try
+ {
+ freshestCRL = CRLDistPoint
+ .getInstance(CertPathValidatorUtilities.getExtensionValue(cert, FRESHEST_CRL));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Freshest CRL extension could not be decoded from certificate.", e);
+ }
+ if (freshestCRL == null)
+ {
+ try
+ {
+ freshestCRL = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ FRESHEST_CRL));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Freshest CRL extension could not be decoded from CRL.", e);
+ }
+ }
+ if (freshestCRL != null)
+ {
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "No new delta CRL locations could be added from Freshest CRL extension.", e);
+ }
+ // get delta CRL(s)
+ try
+ {
+ set.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+ }
+ }
+ }
+ return set;
+ }
+
+ protected static Set[] processCRLA1ii(
+ Date currentDate,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ Set deltaSet = new HashSet();
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ crlselect.setCertificateChecking(cert);
+
+ try
+ {
+ crlselect.addIssuerName(crl.getIssuerX500Principal().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL." + e, e);
+ }
+
+ crlselect.setCompleteCRLEnabled(true);
+ Set completeSet = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRL(s)
+ try
+ {
+ deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+ }
+ }
+ return new Set[]
+ {
+ completeSet,
+ deltaSet};
+ }
+
+
+
+ /**
+ * If use-deltas is set, verify the issuer and scope of the delta CRL.
+ *
+ * @param deltaCRL The delta CRL.
+ * @param completeCRL The complete CRL.
+ * @param pkixParams The PKIX paramaters.
+ * @throws AnnotatedException if an exception occurs.
+ */
+ protected static void processCRLC(
+ X509CRL deltaCRL,
+ X509CRL completeCRL,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (deltaCRL == null)
+ {
+ return;
+ }
+ IssuingDistributionPoint completeidp = null;
+ try
+ {
+ completeidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+ completeCRL, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+
+ if (pkixParams.isUseDeltasEnabled())
+ {
+ // (c) (1)
+ if (!deltaCRL.getIssuerX500Principal().equals(completeCRL.getIssuerX500Principal()))
+ {
+ throw new AnnotatedException("Complete CRL issuer does not match delta CRL issuer.");
+ }
+
+ // (c) (2)
+ IssuingDistributionPoint deltaidp = null;
+ try
+ {
+ deltaidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+ deltaCRL, ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension from delta CRL could not be decoded.", e);
+ }
+
+ boolean match = false;
+ if (completeidp == null)
+ {
+ if (deltaidp == null)
+ {
+ match = true;
+ }
+ }
+ else
+ {
+ if (completeidp.equals(deltaidp))
+ {
+ match = true;
+ }
+ }
+ if (!match)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension from delta CRL and complete CRL does not match.");
+ }
+
+ // (c) (3)
+ ASN1Primitive completeKeyIdentifier = null;
+ try
+ {
+ completeKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+ completeCRL, AUTHORITY_KEY_IDENTIFIER);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Authority key identifier extension could not be extracted from complete CRL.", e);
+ }
+
+ ASN1Primitive deltaKeyIdentifier = null;
+ try
+ {
+ deltaKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+ deltaCRL, AUTHORITY_KEY_IDENTIFIER);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Authority key identifier extension could not be extracted from delta CRL.", e);
+ }
+
+ if (completeKeyIdentifier == null)
+ {
+ throw new AnnotatedException("CRL authority key identifier is null.");
+ }
+
+ if (deltaKeyIdentifier == null)
+ {
+ throw new AnnotatedException("Delta CRL authority key identifier is null.");
+ }
+
+ if (!completeKeyIdentifier.equals(deltaKeyIdentifier))
+ {
+ throw new AnnotatedException(
+ "Delta CRL authority key identifier does not match complete CRL authority key identifier.");
+ }
+ }
+ }
+
+ protected static void processCRLI(
+ Date validDate,
+ X509CRL deltacrl,
+ Object cert,
+ CertStatus certStatus,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (pkixParams.isUseDeltasEnabled() && deltacrl != null)
+ {
+ CertPathValidatorUtilities.getCertStatus(validDate, deltacrl, cert, certStatus);
+ }
+ }
+
+ protected static void processCRLJ(
+ Date validDate,
+ X509CRL completecrl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ CertPathValidatorUtilities.getCertStatus(validDate, completecrl, cert, certStatus);
+ }
+ }
+
+ protected static PKIXPolicyNode prepareCertB(
+ CertPath certPath,
+ int index,
+ List[] policyNodes,
+ PKIXPolicyNode validPolicyTree,
+ int policyMapping)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ // (b)
+ //
+ ASN1Sequence pm = null;
+ try
+ {
+ pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_MAPPINGS));
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+ index);
+ }
+ PKIXPolicyNode _validPolicyTree = validPolicyTree;
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence)pm;
+ Map m_idp = new HashMap();
+ Set s_idp = new HashSet();
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+ String id_p = ((DERObjectIdentifier)mapping.getObjectAt(0)).getId();
+ String sd_p = ((DERObjectIdentifier)mapping.getObjectAt(1)).getId();
+ Set tmp;
+
+ if (!m_idp.containsKey(id_p))
+ {
+ tmp = new HashSet();
+ tmp.add(sd_p);
+ m_idp.put(id_p, tmp);
+ s_idp.add(id_p);
+ }
+ else
+ {
+ tmp = (Set)m_idp.get(id_p);
+ tmp.add(sd_p);
+ }
+ }
+
+ Iterator it_idp = s_idp.iterator();
+ while (it_idp.hasNext())
+ {
+ String id_p = (String)it_idp.next();
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Certificate policies extension could not be decoded.", e, certPath, index);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new CertPathValidatorException(
+ "Policy information could not be decoded.", ex, certPath, index);
+ }
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = CertPathValidatorUtilities
+ .getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be decoded.", ex, certPath,
+ index);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(new ArrayList(), i, (Set)m_idp
+ .get(id_p), p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(
+ _validPolicyTree, policyNodes, node2);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return _validPolicyTree;
+ }
+
+ protected static void prepareNextCertA(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ //
+ // (a) check the policy mappings
+ //
+ ASN1Sequence pm = null;
+ try
+ {
+ pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_MAPPINGS));
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+ index);
+ }
+ if (pm != null)
+ {
+ ASN1Sequence mappings = pm;
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ DERObjectIdentifier issuerDomainPolicy = null;
+ DERObjectIdentifier subjectDomainPolicy = null;
+ try
+ {
+ ASN1Sequence mapping = DERSequence.getInstance(mappings.getObjectAt(j));
+
+ issuerDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(0));
+ subjectDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(1));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension contents could not be decoded.",
+ e, certPath, index);
+ }
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(issuerDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy", null, certPath, index);
+ }
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(subjectDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy,", null, certPath, index);
+ }
+ }
+ }
+ }
+
+ protected static void processCertF(
+ CertPath certPath,
+ int index,
+ PKIXPolicyNode validPolicyTree,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ //
+ // (f)
+ //
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ throw new ExtCertPathValidatorException("No valid policy tree found when one expected.", null, certPath,
+ index);
+ }
+ }
+
+ protected static PKIXPolicyNode processCertE(
+ CertPath certPath,
+ int index,
+ PKIXPolicyNode validPolicyTree)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (e)
+ //
+ ASN1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+ return validPolicyTree;
+ }
+
+ protected static void processCertBC(
+ CertPath certPath,
+ int index,
+ PKIXNameConstraintValidator nameConstraintValidator)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (b), (c) permitted and excluded subtree checking.
+ //
+ if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n)))
+ {
+ X500Principal principal = CertPathValidatorUtilities.getSubjectPrincipal(cert);
+ ASN1InputStream aIn = new ASN1InputStream(principal.getEncoded());
+ ASN1Sequence dns;
+
+ try
+ {
+ dns = DERSequence.getInstance(aIn.readObject());
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Exception extracting subject name when checking subtrees.", e,
+ certPath, index);
+ }
+
+ try
+ {
+ nameConstraintValidator.checkPermittedDN(dns);
+ nameConstraintValidator.checkExcludedDN(dns);
+ }
+ catch (PKIXNameConstraintValidatorException e)
+ {
+ throw new CertPathValidatorException("Subtree check for certificate subject failed.", e, certPath,
+ index);
+ }
+
+ GeneralNames altName = null;
+ try
+ {
+ altName = GeneralNames.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME));
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Subject alternative name extension could not be decoded.", e,
+ certPath, index);
+ }
+ Vector emails = new X509Name(dns).getValues(X509Name.EmailAddress);
+ for (Enumeration e = emails.elements(); e.hasMoreElements();)
+ {
+ String email = (String)e.nextElement();
+ GeneralName emailAsGeneralName = new GeneralName(GeneralName.rfc822Name, email);
+ try
+ {
+ nameConstraintValidator.checkPermitted(emailAsGeneralName);
+ nameConstraintValidator.checkExcluded(emailAsGeneralName);
+ }
+ catch (PKIXNameConstraintValidatorException ex)
+ {
+ throw new CertPathValidatorException(
+ "Subtree check for certificate subject alternative email failed.", ex, certPath, index);
+ }
+ }
+ if (altName != null)
+ {
+ GeneralName[] genNames = null;
+ try
+ {
+ genNames = altName.getNames();
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Subject alternative name contents could not be decoded.", e,
+ certPath, index);
+ }
+ for (int j = 0; j < genNames.length; j++)
+ {
+
+ try
+ {
+ nameConstraintValidator.checkPermitted(genNames[j]);
+ nameConstraintValidator.checkExcluded(genNames[j]);
+ }
+ catch (PKIXNameConstraintValidatorException e)
+ {
+ throw new CertPathValidatorException(
+ "Subtree check for certificate subject alternative name failed.", e, certPath, index);
+ }
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode processCertD(
+ CertPath certPath,
+ int index,
+ Set acceptablePolicies,
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ int inhibitAnyPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (d) policy Information checking against initial policy and
+ // policy mapping
+ //
+ ASN1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies != null && validPolicyTree != null)
+ {
+ //
+ // (d) (1)
+ //
+ Enumeration e = certPolicies.getObjects();
+ Set pols = new HashSet();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+ DERObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+ pols.add(pOid.getId());
+
+ if (!RFC3280CertPathUtilities.ANY_POLICY.equals(pOid.getId()))
+ {
+ Set pq = null;
+ try
+ {
+ pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info set could not be build.", ex,
+ certPath, index);
+ }
+
+ boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies.isEmpty() || acceptablePolicies.contains(RFC3280CertPathUtilities.ANY_POLICY))
+ {
+ acceptablePolicies.clear();
+ acceptablePolicies.addAll(pols);
+ }
+ else
+ {
+ Iterator it = acceptablePolicies.iterator();
+ Set t1 = new HashSet();
+
+ while (it.hasNext())
+ {
+ Object o = it.next();
+
+ if (pols.contains(o))
+ {
+ t1.add(o);
+ }
+ }
+ acceptablePolicies.clear();
+ acceptablePolicies.addAll(t1);
+ }
+
+ //
+ // (d) (2)
+ //
+ if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert)))
+ {
+ e = certPolicies.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+ {
+ Set _apq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+ List _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k);
+
+ Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+ while (_policySetIter.hasNext())
+ {
+ Object _tmp = _policySetIter.next();
+
+ String _policy;
+ if (_tmp instanceof String)
+ {
+ _policy = (String)_tmp;
+ }
+ else if (_tmp instanceof DERObjectIdentifier)
+ {
+ _policy = ((DERObjectIdentifier)_tmp).getId();
+ }
+ else
+ {
+ continue;
+ }
+
+ boolean _found = false;
+ Iterator _childrenIter = _node.getChildren();
+
+ while (_childrenIter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next();
+
+ if (_policy.equals(_child.getValidPolicy()))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ Set _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.add(_policy);
+
+ PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(), i,
+ _newChildExpectedPolicies, _node, _apq, _policy, false);
+ _node.addChild(_newChild);
+ policyNodes[i].add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ PKIXPolicyNode _validPolicyTree = validPolicyTree;
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(_validPolicyTree, policyNodes,
+ node);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensionOids != null)
+ {
+ boolean critical = criticalExtensionOids.contains(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+
+ List nodes = policyNodes[i];
+ for (int j = 0; j < nodes.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j);
+ node.setCritical(critical);
+ }
+ }
+ return _validPolicyTree;
+ }
+ return null;
+ }
+
+ protected static void processCertA(
+ CertPath certPath,
+ ExtendedPKIXParameters paramsPKIX,
+ int index,
+ PublicKey workingPublicKey,
+ boolean verificationAlreadyPerformed,
+ X500Principal workingIssuerName,
+ X509Certificate sign)
+ throws ExtCertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (a) verify
+ //
+ if (!verificationAlreadyPerformed)
+ {
+ try
+ {
+ // (a) (1)
+ //
+ CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
+ paramsPKIX.getSigProvider());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+ }
+ }
+
+ try
+ {
+ // (a) (2)
+ //
+ cert.checkValidity(CertPathValidatorUtilities
+ .getValidCertDateFromValidityModel(paramsPKIX, certPath, index));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
+ }
+
+ //
+ // (a) (3)
+ //
+ if (paramsPKIX.isRevocationEnabled())
+ {
+ try
+ {
+ checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX,
+ certPath, index), sign, workingPublicKey, certs);
+ }
+ catch (AnnotatedException e)
+ {
+ Throwable cause = e;
+ if (null != e.getCause())
+ {
+ cause = e.getCause();
+ }
+ throw new ExtCertPathValidatorException(e.getMessage(), cause, certPath, index);
+ }
+ }
+
+ //
+ // (a) (4) name chaining
+ //
+ if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
+ {
+ throw new ExtCertPathValidatorException("IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)
+ + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
+ certPath, index);
+ }
+ }
+
+ protected static int prepareNextCertI1(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (i)
+ //
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ try
+ {
+
+ ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+ if (constraint.getTagNo() == 0)
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < explicitPolicy)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+ e, certPath, index);
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static int prepareNextCertI2(
+ CertPath certPath,
+ int index,
+ int policyMapping)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (i)
+ //
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ try
+ {
+ ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+ if (constraint.getTagNo() == 1)
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < policyMapping)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+ e, certPath, index);
+ }
+ }
+ }
+ return policyMapping;
+ }
+
+ protected static void prepareNextCertG(
+ CertPath certPath,
+ int index,
+ PKIXNameConstraintValidator nameConstraintValidator)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (g) handle the name constraints extension
+ //
+ NameConstraints nc = null;
+ try
+ {
+ ASN1Sequence ncSeq = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.NAME_CONSTRAINTS));
+ if (ncSeq != null)
+ {
+ nc = NameConstraints.getInstance(ncSeq);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Name constraints extension could not be decoded.", e, certPath,
+ index);
+ }
+ if (nc != null)
+ {
+
+ //
+ // (g) (1) permitted subtrees
+ //
+ GeneralSubtree[] permitted = nc.getPermittedSubtrees();
+ if (permitted != null)
+ {
+ try
+ {
+ nameConstraintValidator.intersectPermittedSubtree(permitted);
+ }
+ catch (Exception ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ GeneralSubtree[] excluded = nc.getExcludedSubtrees();
+ if (excluded != null)
+ {
+ for (int i = 0; i != excluded.length; i++)
+ try
+ {
+ nameConstraintValidator.addExcludedSubtree(excluded[i]);
+ }
+ catch (Exception ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks a distribution point for revocation information for the
+ * certificate <code>cert</code>.
+ *
+ * @param dp The distribution point to consider.
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param certStatus The current certificate revocation status.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ private static void checkCRL(
+ DistributionPoint dp,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate defaultCRLSignCert,
+ PublicKey defaultCRLSignKey,
+ CertStatus certStatus,
+ ReasonsMask reasonMask,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ Date currentDate = new Date(System.currentTimeMillis());
+ if (validDate.getTime() > currentDate.getTime())
+ {
+ throw new AnnotatedException("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPKIXParameters and are in
+ * getAdditionalStore()
+ */
+
+ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, cert, currentDate, paramsPKIX);
+ boolean validCrlFound = false;
+ AnnotatedException lastException = null;
+ Iterator crl_iter = crls.iterator();
+
+ while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons())
+ {
+ try
+ {
+ X509CRL crl = (X509CRL)crl_iter.next();
+
+ // (d)
+ ReasonsMask interimReasonsMask = RFC3280CertPathUtilities.processCRLD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.hasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ Set keys = RFC3280CertPathUtilities.processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey,
+ paramsPKIX, certPathCerts);
+ // (g)
+ PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys);
+
+ X509CRL deltaCRL = null;
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRLs
+ Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs, key);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL validity time
+ */
+
+ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (cert.getNotAfter().getTime() < crl.getThisUpdate().getTime())
+ {
+ throw new AnnotatedException("No valid CRL for current time found.");
+ }
+ }
+
+ RFC3280CertPathUtilities.processCRLB1(dp, cert, crl);
+
+ // (b) (2)
+ RFC3280CertPathUtilities.processCRLB2(dp, cert, crl);
+
+ // (c)
+ RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL, cert, certStatus, paramsPKIX);
+
+ // (j)
+ RFC3280CertPathUtilities.processCRLJ(validDate, crl, cert, certStatus);
+
+ // (k)
+ if (certStatus.getCertStatus() == CRLReason.removeFromCRL)
+ {
+ certStatus.setCertStatus(CertStatus.UNREVOKED);
+ }
+
+ // update reasons mask
+ reasonMask.addReasons(interimReasonsMask);
+
+ Set criticalExtensions = crl.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId());
+ criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId());
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new AnnotatedException("CRL contains unsupported critical extensions.");
+ }
+ }
+
+ if (deltaCRL != null)
+ {
+ criticalExtensions = deltaCRL.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId());
+ criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId());
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new AnnotatedException("Delta CRL contains unsupported critical extension.");
+ }
+ }
+ }
+
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+
+ /**
+ * Checks a certificate if it is revoked.
+ *
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param sign The issuer certificate of the certificate <code>cert</code>.
+ * @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ protected static void checkCRLs(
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate sign,
+ PublicKey workingPublicKey,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ AnnotatedException lastException = null;
+ CRLDistPoint crldp = null;
+ try
+ {
+ crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("CRL distribution point extension could not be read.", e);
+ }
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ boolean validCrlFound = false;
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Distribution points could not be read.", e);
+ }
+ if (dps != null)
+ {
+ for (int i = 0; i < dps.length && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons(); i++)
+ {
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone();
+ try
+ {
+ checkCRL(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the process
+ * above with any available CRLs not specified in a distribution point
+ * but issued by the certificate issuer.
+ */
+
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons())
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer fields
+ * omitted and a distribution point name of the certificate
+ * issuer.
+ */
+ ASN1Primitive issuer = null;
+ try
+ {
+ issuer = new ASN1InputStream(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded())
+ .readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuer from certificate for CRL could not be reencoded.", e);
+ }
+ DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.directoryName, issuer))), null, null);
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone();
+ checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask,
+ certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ if (lastException instanceof AnnotatedException)
+ {
+ throw lastException;
+ }
+
+ throw new AnnotatedException("No valid CRL found.", lastException);
+ }
+ if (certStatus.getCertStatus() != CertStatus.UNREVOKED)
+ {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
+ df.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String message = "Certificate revocation after " + df.format(certStatus.getRevocationDate());
+ message += ", reason: " + crlReasons[certStatus.getCertStatus()];
+ throw new AnnotatedException(message);
+ }
+ if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ certStatus.setCertStatus(CertStatus.UNDETERMINED);
+ }
+ if (certStatus.getCertStatus() == CertStatus.UNDETERMINED)
+ {
+ throw new AnnotatedException("Certificate status could not be determined.");
+ }
+ }
+
+ protected static int prepareNextCertJ(
+ CertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (j)
+ //
+ DERInteger iap = null;
+ try
+ {
+ iap = DERInteger.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.INHIBIT_ANY_POLICY));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Inhibit any-policy extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.getValue().intValue();
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ {
+ return _inhibitAnyPolicy;
+ }
+ }
+ return inhibitAnyPolicy;
+ }
+
+ protected static void prepareNextCertK(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (k)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ if (!(bc.isCA()))
+ {
+ throw new CertPathValidatorException("Not a CA certificate");
+ }
+ }
+ else
+ {
+ throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+ }
+ }
+
+ protected static int prepareNextCertL(
+ CertPath certPath,
+ int index,
+ int maxPathLength)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (l)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ throw new ExtCertPathValidatorException("Max path length not greater than zero", null, certPath, index);
+ }
+
+ return maxPathLength - 1;
+ }
+ return maxPathLength;
+ }
+
+ protected static int prepareNextCertM(
+ CertPath certPath,
+ int index,
+ int maxPathLength)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+
+ //
+ // (m)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.intValue();
+
+ if (_plc < maxPathLength)
+ {
+ return _plc;
+ }
+ }
+ }
+ return maxPathLength;
+ }
+
+ protected static void prepareNextCertN(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+
+ //
+ // (n)
+ //
+ boolean[] _usage = cert.getKeyUsage();
+
+ if ((_usage != null) && !_usage[RFC3280CertPathUtilities.KEY_CERT_SIGN])
+ {
+ throw new ExtCertPathValidatorException(
+ "Issuer certificate keyusage extension is critical and does not permit key signing.", null,
+ certPath, index);
+ }
+ }
+
+ protected static void prepareNextCertO(
+ CertPath certPath,
+ int index,
+ Set criticalExtensions,
+ List pathCheckers)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (o)
+ //
+
+ Iterator tmpIter;
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+ }
+ }
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath,
+ index);
+ }
+ }
+
+ protected static int prepareNextCertH1(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (1)
+ //
+ if (explicitPolicy != 0)
+ {
+ return explicitPolicy - 1;
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static int prepareNextCertH2(
+ CertPath certPath,
+ int index,
+ int policyMapping)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (2)
+ //
+ if (policyMapping != 0)
+ {
+ return policyMapping - 1;
+ }
+ }
+ return policyMapping;
+ }
+
+ protected static int prepareNextCertH3(
+ CertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (3)
+ //
+ if (inhibitAnyPolicy != 0)
+ {
+ return inhibitAnyPolicy - 1;
+ }
+ }
+ return inhibitAnyPolicy;
+ }
+
+ protected static final String[] crlReasons = new String[]
+ {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ protected static int wrapupCertA(
+ int explicitPolicy,
+ X509Certificate cert)
+ {
+ //
+ // (a)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0))
+ {
+ explicitPolicy--;
+ }
+ return explicitPolicy;
+ }
+
+ protected static int wrapupCertB(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (b)
+ //
+ int tmpInt;
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
+ }
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ try
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
+ index);
+ }
+ if (tmpInt == 0)
+ {
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static void wrapupCertF(
+ CertPath certPath,
+ int index,
+ List pathCheckers,
+ Set criticalExtensions)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ Iterator tmpIter;
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException("Additional certificate path checker failed.", e, certPath,
+ index);
+ }
+ }
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath,
+ index);
+ }
+ }
+
+ protected static PKIXPolicyNode wrapupCertG(
+ CertPath certPath,
+ ExtendedPKIXParameters paramsPKIX,
+ Set userInitialPolicySet,
+ int index,
+ List[] policyNodes,
+ PKIXPolicyNode validPolicyTree,
+ Set acceptablePolicies)
+ throws CertPathValidatorException
+ {
+ int n = certPath.getCertificates().size();
+ //
+ // (g)
+ //
+ PKIXPolicyNode intersection;
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+ certPath, index);
+ }
+ intersection = null;
+ }
+ else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g)
+ // (ii)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ if (acceptablePolicies.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+ certPath, index);
+ }
+ else
+ {
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ _validPolicyNodeSet.add(_iter.next());
+ }
+ }
+ }
+ }
+
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!acceptablePolicies.contains(_validPolicy))
+ {
+ // validPolicyTree =
+ // removePolicyNode(validPolicyTree, policyNodes,
+ // _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree,
+ policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in
+ // RFC3280.
+ // However, as far as the validation result is concerned, both
+ // produce
+ // adequate result. The only difference is whether AnyPolicy is
+ // remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+ if (!RFC3280CertPathUtilities.ANY_POLICY.equals(_c_node.getValidPolicy()))
+ {
+ _validPolicyNodeSet.add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!userInitialPolicySet.contains(_validPolicy))
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes,
+ node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ return intersection;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java
new file mode 100644
index 000000000..f90154c1e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java
@@ -0,0 +1,703 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.PKIXAttrCertChecker;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CertStoreSelector;
+
+class RFC3281CertPathUtilities
+{
+
+ private static final String TARGET_INFORMATION = X509Extensions.TargetInformation
+ .getId();
+
+ private static final String NO_REV_AVAIL = X509Extensions.NoRevAvail
+ .getId();
+
+ private static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints
+ .getId();
+
+ private static final String AUTHORITY_INFO_ACCESS = X509Extensions.AuthorityInfoAccess
+ .getId();
+
+ protected static void processAttrCert7(X509AttributeCertificate attrCert,
+ CertPath certPath, CertPath holderCertPath,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ // TODO:
+ // AA Controls
+ // Attribute encryption
+ // Proxy
+ Set set = attrCert.getCriticalExtensionOIDs();
+ // 7.1
+ // process extensions
+
+ // target information checked in step 6 / X509AttributeCertStoreSelector
+ if (set.contains(TARGET_INFORMATION))
+ {
+ try
+ {
+ TargetInformation.getInstance(CertPathValidatorUtilities
+ .getExtensionValue(attrCert, TARGET_INFORMATION));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Target information extension could not be read.", e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Target information extension could not be read.", e);
+ }
+ }
+ set.remove(TARGET_INFORMATION);
+ for (Iterator it = pkixParams.getAttrCertCheckers().iterator(); it
+ .hasNext();)
+ {
+ ((PKIXAttrCertChecker) it.next()).check(attrCert, certPath,
+ holderCertPath, set);
+ }
+ if (!set.isEmpty())
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate contains unsupported critical extensions: "
+ + set);
+ }
+ }
+
+ /**
+ * Checks if an attribute certificate is revoked.
+ *
+ * @param attrCert Attribute certificate to check if it is revoked.
+ * @param paramsPKIX PKIX parameters.
+ * @param issuerCert The issuer certificate of the attribute certificate
+ * <code>attrCert</code>.
+ * @param validDate The date when the certificate revocation status should
+ * be checked.
+ * @param certPathCerts The certificates of the certification path to be
+ * checked.
+ *
+ * @throws CertPathValidatorException if the certificate is revoked or the
+ * status cannot be checked or some error occurs.
+ */
+ protected static void checkCRLs(X509AttributeCertificate attrCert,
+ ExtendedPKIXParameters paramsPKIX, X509Certificate issuerCert,
+ Date validDate, List certPathCerts) throws CertPathValidatorException
+ {
+ if (paramsPKIX.isRevocationEnabled())
+ {
+ // check if revocation is available
+ if (attrCert.getExtensionValue(NO_REV_AVAIL) == null)
+ {
+ CRLDistPoint crldp = null;
+ try
+ {
+ crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities
+ .getExtensionValue(attrCert, CRL_DISTRIBUTION_POINTS));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(
+ "CRL distribution point extension could not be read.",
+ e);
+ }
+ try
+ {
+ CertPathValidatorUtilities
+ .addAdditionalStoresFromCRLDistributionPoint(crldp,
+ paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(
+ "No additional CRL locations could be decoded from CRL distribution point extension.",
+ e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ AnnotatedException lastException = null;
+ boolean validCrlFound = false;
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Distribution points could not be read.", e);
+ }
+ try
+ {
+ for (int i = 0; i < dps.length
+ && certStatus.getCertStatus() == CertStatus.UNREVOKED
+ && !reasonsMask.isAllReasons(); i++)
+ {
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters) paramsPKIX
+ .clone();
+ checkCRL(dps[i], attrCert, paramsPKIXClone,
+ validDate, issuerCert, certStatus, reasonsMask,
+ certPathCerts);
+ validCrlFound = true;
+ }
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = new AnnotatedException(
+ "No valid CRL for distribution point found.", e);
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the
+ * process above with any available CRLs not specified in a
+ * distribution point but issued by the certificate issuer.
+ */
+
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED
+ && !reasonsMask.isAllReasons())
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer
+ * fields omitted and a distribution point name of the
+ * certificate issuer.
+ */
+ ASN1Primitive issuer = null;
+ try
+ {
+
+ issuer = new ASN1InputStream(
+ ((X500Principal) attrCert.getIssuer()
+ .getPrincipals()[0]).getEncoded())
+ .readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuer from certificate for CRL could not be reencoded.",
+ e);
+ }
+ DistributionPoint dp = new DistributionPoint(
+ new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.directoryName,
+ issuer))), null, null);
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters) paramsPKIX
+ .clone();
+ checkCRL(dp, attrCert, paramsPKIXClone, validDate,
+ issuerCert, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = new AnnotatedException(
+ "No valid CRL for distribution point found.", e);
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ throw new ExtCertPathValidatorException(
+ "No valid CRL found.", lastException);
+ }
+ if (certStatus.getCertStatus() != CertStatus.UNREVOKED)
+ {
+ String message = "Attribute certificate revocation after "
+ + certStatus.getRevocationDate();
+ message += ", reason: "
+ + RFC3280CertPathUtilities.crlReasons[certStatus
+ .getCertStatus()];
+ throw new CertPathValidatorException(message);
+ }
+ if (!reasonsMask.isAllReasons()
+ && certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ certStatus.setCertStatus(CertStatus.UNDETERMINED);
+ }
+ if (certStatus.getCertStatus() == CertStatus.UNDETERMINED)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate status could not be determined.");
+ }
+
+ }
+ else
+ {
+ if (attrCert.getExtensionValue(CRL_DISTRIBUTION_POINTS) != null
+ || attrCert.getExtensionValue(AUTHORITY_INFO_ACCESS) != null)
+ {
+ throw new CertPathValidatorException(
+ "No rev avail extension is set, but also an AC revocation pointer.");
+ }
+ }
+ }
+ }
+
+ protected static void additionalChecks(X509AttributeCertificate attrCert,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ // 1
+ for (Iterator it = pkixParams.getProhibitedACAttributes().iterator(); it
+ .hasNext();)
+ {
+ String oid = (String) it.next();
+ if (attrCert.getAttributes(oid) != null)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate contains prohibited attribute: "
+ + oid + ".");
+ }
+ }
+ for (Iterator it = pkixParams.getNecessaryACAttributes().iterator(); it
+ .hasNext();)
+ {
+ String oid = (String) it.next();
+ if (attrCert.getAttributes(oid) == null)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate does not contain necessary attribute: "
+ + oid + ".");
+ }
+ }
+ }
+
+ protected static void processAttrCert5(X509AttributeCertificate attrCert,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ try
+ {
+ attrCert.checkValidity(CertPathValidatorUtilities
+ .getValidDate(pkixParams));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Attribute certificate is not valid.", e);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Attribute certificate is not valid.", e);
+ }
+ }
+
+ protected static void processAttrCert4(X509Certificate acIssuerCert,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ Set set = pkixParams.getTrustedACIssuers();
+ boolean trusted = false;
+ for (Iterator it = set.iterator(); it.hasNext();)
+ {
+ TrustAnchor anchor = (TrustAnchor) it.next();
+ if (acIssuerCert.getSubjectX500Principal().getName("RFC2253")
+ .equals(anchor.getCAName())
+ || acIssuerCert.equals(anchor.getTrustedCert()))
+ {
+ trusted = true;
+ }
+ }
+ if (!trusted)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate issuer is not directly trusted.");
+ }
+ }
+
+ protected static void processAttrCert3(X509Certificate acIssuerCert,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ if (acIssuerCert.getKeyUsage() != null
+ && (!acIssuerCert.getKeyUsage()[0] && !acIssuerCert.getKeyUsage()[1]))
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate issuer public key cannot be used to validate digital signatures.");
+ }
+ if (acIssuerCert.getBasicConstraints() != -1)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate issuer is also a public key certificate issuer.");
+ }
+ }
+
+ protected static CertPathValidatorResult processAttrCert2(
+ CertPath certPath, ExtendedPKIXParameters pkixParams)
+ throws CertPathValidatorException
+ {
+ CertPathValidator validator = null;
+ try
+ {
+ validator = CertPathValidator.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Support class could not be created.", e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Support class could not be created.", e);
+ }
+ try
+ {
+ return validator.validate(certPath, pkixParams);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Certification path for issuer certificate of attribute certificate could not be validated.",
+ e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // must be a programming error
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ /**
+ * Searches for a holder public key certificate and verifies its
+ * certification path.
+ *
+ * @param attrCert the attribute certificate.
+ * @param pkixParams The PKIX parameters.
+ * @return The certificate path of the holder certificate.
+ * @throws AnnotatedException if
+ * <ul>
+ * <li>no public key certificate can be found although holder
+ * information is given by an entity name or a base certificate
+ * ID
+ * <li>support classes cannot be created
+ * <li>no certification path for the public key certificate can
+ * be built
+ * </ul>
+ */
+ protected static CertPath processAttrCert1(
+ X509AttributeCertificate attrCert, ExtendedPKIXParameters pkixParams)
+ throws CertPathValidatorException
+ {
+ CertPathBuilderResult result = null;
+ // find holder PKCs
+ Set holderPKCs = new HashSet();
+ if (attrCert.getHolder().getIssuer() != null)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ selector.setSerialNumber(attrCert.getHolder().getSerialNumber());
+ Principal[] principals = attrCert.getHolder().getIssuer();
+ for (int i = 0; i < principals.length; i++)
+ {
+ try
+ {
+ if (principals[i] instanceof X500Principal)
+ {
+ selector.setIssuer(((X500Principal)principals[i])
+ .getEncoded());
+ }
+ holderPKCs.addAll(CertPathValidatorUtilities
+ .findCertificates(selector, pkixParams.getStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Unable to encode X500 principal.", e);
+ }
+ }
+ if (holderPKCs.isEmpty())
+ {
+ throw new CertPathValidatorException(
+ "Public key certificate specified in base certificate ID for attribute certificate cannot be found.");
+ }
+ }
+ if (attrCert.getHolder().getEntityNames() != null)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ Principal[] principals = attrCert.getHolder().getEntityNames();
+ for (int i = 0; i < principals.length; i++)
+ {
+ try
+ {
+ if (principals[i] instanceof X500Principal)
+ {
+ selector.setIssuer(((X500Principal) principals[i])
+ .getEncoded());
+ }
+ holderPKCs.addAll(CertPathValidatorUtilities
+ .findCertificates(selector, pkixParams.getStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Unable to encode X500 principal.", e);
+ }
+ }
+ if (holderPKCs.isEmpty())
+ {
+ throw new CertPathValidatorException(
+ "Public key certificate specified in entity name for attribute certificate cannot be found.");
+ }
+ }
+ // verify cert paths for PKCs
+ ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
+ .getInstance(pkixParams);
+ CertPathValidatorException lastException = null;
+ for (Iterator it = holderPKCs.iterator(); it.hasNext();)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ selector.setCertificate((X509Certificate) it.next());
+ params.setTargetConstraints(selector);
+ CertPathBuilder builder = null;
+ try
+ {
+ builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Support class could not be created.", e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Support class could not be created.", e);
+ }
+ try
+ {
+ result = builder.build(ExtendedPKIXBuilderParameters
+ .getInstance(params));
+ }
+ catch (CertPathBuilderException e)
+ {
+ lastException = new ExtCertPathValidatorException(
+ "Certification path for public key certificate of attribute certificate could not be build.",
+ e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // must be a programming error
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+ if (lastException != null)
+ {
+ throw lastException;
+ }
+ return result.getCertPath();
+ }
+
+ /**
+ *
+ * Checks a distribution point for revocation information for the
+ * certificate <code>attrCert</code>.
+ *
+ * @param dp The distribution point to consider.
+ * @param attrCert The attribute certificate which should be checked.
+ * @param paramsPKIX PKIX parameters.
+ * @param validDate The date when the certificate revocation status should
+ * be checked.
+ * @param issuerCert Certificate to check if it is revoked.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path to be
+ * checked.
+ * @throws AnnotatedException if the certificate is revoked or the status
+ * cannot be checked or some error occurs.
+ */
+ private static void checkCRL(DistributionPoint dp,
+ X509AttributeCertificate attrCert, ExtendedPKIXParameters paramsPKIX,
+ Date validDate, X509Certificate issuerCert, CertStatus certStatus,
+ ReasonsMask reasonMask, List certPathCerts) throws AnnotatedException
+ {
+
+ /*
+ * 4.3.6 No Revocation Available
+ *
+ * The noRevAvail extension, defined in [X.509-2000], allows an AC
+ * issuer to indicate that no revocation information will be made
+ * available for this AC.
+ */
+ if (attrCert.getExtensionValue(X509Extensions.NoRevAvail.getId()) != null)
+ {
+ return;
+ }
+ Date currentDate = new Date(System.currentTimeMillis());
+ if (validDate.getTime() > currentDate.getTime())
+ {
+ throw new AnnotatedException("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPKIXParameters and are in
+ * getAdditionalStore()
+ */
+
+ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, attrCert,
+ currentDate, paramsPKIX);
+ boolean validCrlFound = false;
+ AnnotatedException lastException = null;
+ Iterator crl_iter = crls.iterator();
+
+ while (crl_iter.hasNext()
+ && certStatus.getCertStatus() == CertStatus.UNREVOKED
+ && !reasonMask.isAllReasons())
+ {
+ try
+ {
+ X509CRL crl = (X509CRL) crl_iter.next();
+
+ // (d)
+ ReasonsMask interimReasonsMask = RFC3280CertPathUtilities
+ .processCRLD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.hasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ Set keys = RFC3280CertPathUtilities.processCRLF(crl, attrCert,
+ null, null, paramsPKIX, certPathCerts);
+ // (g)
+ PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys);
+
+ X509CRL deltaCRL = null;
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRLs
+ Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(
+ currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs,
+ key);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL vality time
+ */
+
+ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (attrCert.getNotAfter().getTime() < crl.getThisUpdate()
+ .getTime())
+ {
+ throw new AnnotatedException(
+ "No valid CRL for current time found.");
+ }
+ }
+
+ RFC3280CertPathUtilities.processCRLB1(dp, attrCert, crl);
+
+ // (b) (2)
+ RFC3280CertPathUtilities.processCRLB2(dp, attrCert, crl);
+
+ // (c)
+ RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL,
+ attrCert, certStatus, paramsPKIX);
+
+ // (j)
+ RFC3280CertPathUtilities.processCRLJ(validDate, crl, attrCert,
+ certStatus);
+
+ // (k)
+ if (certStatus.getCertStatus() == CRLReason.removeFromCRL)
+ {
+ certStatus.setCertStatus(CertStatus.UNREVOKED);
+ }
+
+ // update reasons mask
+ reasonMask.addReasons(interimReasonsMask);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/ReasonsMask.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/ReasonsMask.java
new file mode 100644
index 000000000..dad7acaa3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/ReasonsMask.java
@@ -0,0 +1,101 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.asn1.x509.ReasonFlags;
+
+/**
+ * This class helps to handle CRL revocation reasons mask. Each CRL handles a
+ * certain set of revocation reasons.
+ */
+class ReasonsMask
+{
+ private int _reasons;
+
+ /**
+ * Constructs are reason mask with the reasons.
+ *
+ * @param reasons The reasons.
+ */
+ ReasonsMask(ReasonFlags reasons)
+ {
+ _reasons = reasons.intValue();
+ }
+
+ private ReasonsMask(int reasons)
+ {
+ _reasons = reasons;
+ }
+
+ /**
+ * A reason mask with no reason.
+ *
+ */
+ ReasonsMask()
+ {
+ this(0);
+ }
+
+ /**
+ * A mask with all revocation reasons.
+ */
+ static final ReasonsMask allReasons = new ReasonsMask(ReasonFlags.aACompromise
+ | ReasonFlags.affiliationChanged | ReasonFlags.cACompromise
+ | ReasonFlags.certificateHold | ReasonFlags.cessationOfOperation
+ | ReasonFlags.keyCompromise | ReasonFlags.privilegeWithdrawn
+ | ReasonFlags.unused | ReasonFlags.superseded);
+
+ /**
+ * Adds all reasons from the reasons mask to this mask.
+ *
+ * @param mask The reasons mask to add.
+ */
+ void addReasons(ReasonsMask mask)
+ {
+ _reasons = _reasons | mask.getReasons();
+ }
+
+ /**
+ * Returns <code>true</code> if this reasons mask contains all possible
+ * reasons.
+ *
+ * @return <code>true</code> if this reasons mask contains all possible
+ * reasons.
+ */
+ boolean isAllReasons()
+ {
+ return _reasons == allReasons._reasons ? true : false;
+ }
+
+ /**
+ * Intersects this mask with the given reasons mask.
+ *
+ * @param mask The mask to intersect with.
+ * @return The intersection of this and teh given mask.
+ */
+ ReasonsMask intersect(ReasonsMask mask)
+ {
+ ReasonsMask _mask = new ReasonsMask();
+ _mask.addReasons(new ReasonsMask(_reasons & mask.getReasons()));
+ return _mask;
+ }
+
+ /**
+ * Returns <code>true</code> if the passed reasons mask has new reasons.
+ *
+ * @param mask The reasons mask which should be tested for new reasons.
+ * @return <code>true</code> if the passed reasons mask has new reasons.
+ */
+ boolean hasNewReasons(ReasonsMask mask)
+ {
+ return ((_reasons | mask.getReasons() ^ _reasons) != 0);
+ }
+
+ /**
+ * Returns the reasons in this mask.
+ *
+ * @return Returns the reasons.
+ */
+ int getReasons()
+ {
+ return _reasons;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509AttrCertParser.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509AttrCertParser.java
new file mode 100644
index 000000000..6a44ade19
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509AttrCertParser.java
@@ -0,0 +1,156 @@
+package org.spongycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509StreamParserSpi;
+import org.spongycastle.x509.X509V2AttributeCertificate;
+import org.spongycastle.x509.util.StreamParsingException;
+
+public class X509AttrCertParser
+ extends X509StreamParserSpi
+{
+ private static final PEMUtil PEM_PARSER = new PEMUtil("ATTRIBUTE CERTIFICATE");
+
+ private ASN1Set sData = null;
+ private int sDataObjectCount = 0;
+ private InputStream currentStream = null;
+
+ private X509AttributeCertificate readDERCertificate(
+ InputStream in)
+ throws IOException
+ {
+ ASN1InputStream dIn = new ASN1InputStream(in);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof DERObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sData = new SignedData(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+
+ return getCertificate();
+ }
+ }
+
+ return new X509V2AttributeCertificate(seq.getEncoded());
+ }
+
+ private X509AttributeCertificate getCertificate()
+ throws IOException
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.size())
+ {
+ Object obj = sData.getObjectAt(sDataObjectCount++);
+
+ if (obj instanceof ASN1TaggedObject && ((ASN1TaggedObject)obj).getTagNo() == 2)
+ {
+ return new X509V2AttributeCertificate(
+ ASN1Sequence.getInstance((ASN1TaggedObject)obj, false).getEncoded());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private X509AttributeCertificate readPEMCertificate(
+ InputStream in)
+ throws IOException
+ {
+ ASN1Sequence seq = PEM_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return new X509V2AttributeCertificate(seq.getEncoded());
+ }
+
+ return null;
+ }
+
+ public void engineInit(InputStream in)
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+
+ if (!currentStream.markSupported())
+ {
+ currentStream = new BufferedInputStream(currentStream);
+ }
+ }
+
+ public Object engineRead()
+ throws StreamParsingException
+ {
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.size())
+ {
+ return getCertificate();
+ }
+ else
+ {
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ currentStream.mark(10);
+ int tag = currentStream.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ currentStream.reset();
+ return readPEMCertificate(currentStream);
+ }
+ else
+ {
+ currentStream.reset();
+ return readDERCertificate(currentStream);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new StreamParsingException(e.toString(), e);
+ }
+ }
+
+ public Collection engineReadAll()
+ throws StreamParsingException
+ {
+ X509AttributeCertificate cert;
+ List certs = new ArrayList();
+
+ while ((cert = (X509AttributeCertificate)engineRead()) != null)
+ {
+ certs.add(cert);
+ }
+
+ return certs;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLEntryObject.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLEntryObject.java
new file mode 100644
index 000000000..348c3ab23
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLEntryObject.java
@@ -0,0 +1,318 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.X509Extension;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+public class X509CRLEntryObject extends X509CRLEntry
+{
+ private TBSCertList.CRLEntry c;
+
+ private X500Name certificateIssuer;
+ private int hashValue;
+ private boolean isHashValueSet;
+
+ public X509CRLEntryObject(TBSCertList.CRLEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = null;
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+ * is <code>false</code> {@link #getCertificateIssuer()} will always
+ * return <code>null</code>, <code>previousCertificateIssuer</code> is
+ * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+ * has no certificate issuer CRL entry extension
+ * <code>previousCertificateIssuer</code> is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TBSCertList.CRLEntry object.
+ * @param isIndirect
+ * <code>true</code> if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CRLEntry.
+ */
+ public X509CRLEntryObject(
+ TBSCertList.CRLEntry c,
+ boolean isIndirect,
+ X500Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+ }
+
+ /**
+ * Will return true if any extensions are present and marked as critical as
+ * we currently don't handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ return extns != null && !extns.isEmpty();
+ }
+
+ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ Extension ext = getExtension(Extension.certificateIssuer);
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.getInstance(ext.getParsedValue()).getNames();
+ for (int i = 0; i < names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ return X500Name.getInstance(names[i].getName());
+ }
+ }
+ return null;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public X500Principal getCertificateIssuer()
+ {
+ if (certificateIssuer == null)
+ {
+ return null;
+ }
+ try
+ {
+ return new X500Principal(certificateIssuer.getEncoded());
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ private Extension getExtension(ASN1ObjectIdentifier oid)
+ {
+ Extensions exts = c.getExtensions();
+
+ if (exts != null)
+ {
+ return exts.getExtension(oid);
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extension ext = getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Cache the hashCode value - calculating it with the standard method.
+ * @return calculated hashCode.
+ */
+ public int hashCode()
+ {
+ if (!isHashValueSet)
+ {
+ hashValue = super.hashCode();
+ isHashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (o instanceof X509CRLEntryObject)
+ {
+ X509CRLEntryObject other = (X509CRLEntryObject)o;
+
+ return this.c.equals(other.c);
+ }
+
+ return super.equals(this);
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getUserCertificate().getValue();
+ }
+
+ public Date getRevocationDate()
+ {
+ return c.getRevocationDate().getDate();
+ }
+
+ public boolean hasExtensions()
+ {
+ return c.getExtensions() != null;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl);
+ buf.append(" certificateIssuer: ").append(this.getCertificateIssuer()).append(nl);
+
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+ if (e.hasMoreElements())
+ {
+ buf.append(" crlEntryExtensions:").append(nl);
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(X509Extension.reasonCode))
+ {
+ buf.append(CRLReason.getInstance(ASN1Enumerated.getInstance(dIn.readObject()))).append(nl);
+ }
+ else if (oid.equals(X509Extension.certificateIssuer))
+ {
+ buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLObject.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLObject.java
new file mode 100644
index 000000000..2f94b875d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLObject.java
@@ -0,0 +1,625 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLNumber;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.encoders.Hex;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+public class X509CRLObject
+ extends X509CRL
+{
+ private CertificateList c;
+ private String sigAlgName;
+ private byte[] sigAlgParams;
+ private boolean isIndirect;
+ private boolean isHashCodeSet = false;
+ private int hashCodeValue;
+
+ static boolean isIndirectCRL(X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+ return idp != null
+ && IssuingDistributionPoint.getInstance(ASN1OctetString.getInstance(idp).getOctets()).isIndirectCRL();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCRLException(
+ "Exception reading IssuingDistributionPoint", e);
+ }
+ }
+
+ public X509CRLObject(
+ CertificateList c)
+ throws CRLException
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = isIndirectCRL(this);
+ }
+ catch (Exception e)
+ {
+ throw new CRLException("CRL contents invalid: " + e);
+ }
+ }
+
+ /**
+ * Will return true if any extensions are present and marked
+ * as critical as we currently dont handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ if (extns == null)
+ {
+ return false;
+ }
+
+ extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+ return !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ if (this.getVersion() == 2)
+ {
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertList().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ verify(key, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+ {
+ throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+ }
+
+ Signature sig;
+
+ if (sigProvider != null)
+ {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+ else
+ {
+ sig = Signature.getInstance(getSigAlgName());
+ }
+
+ sig.initVerify(key);
+ sig.update(this.getTBSCertList());
+
+ if (!sig.verify(this.getSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public Principal getIssuerDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+ }
+
+ public X500Principal getIssuerX500Principal()
+ {
+ try
+ {
+ return new X500Principal(c.getIssuer().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Date getThisUpdate()
+ {
+ return c.getThisUpdate().getDate();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (c.getNextUpdate() != null)
+ {
+ return c.getNextUpdate().getDate();
+ }
+
+ return null;
+ }
+
+ private Set loadCRLEntries()
+ {
+ Set entrySet = new HashSet();
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = null; // the issuer
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+ X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ entrySet.add(crlEntry);
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return entrySet;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+ {
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = null; // the issuer
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+ if (serialNumber.equals(entry.getUserCertificate().getValue()))
+ {
+ return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getRevokedCertificates()
+ {
+ Set entrySet = loadCRLEntries();
+
+ if (!entrySet.isEmpty())
+ {
+ return Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public byte[] getTBSCertList()
+ throws CRLException
+ {
+ try
+ {
+ return c.getTBSCertList().getEncoded("DER");
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ public String getSigAlgName()
+ {
+ return sigAlgName;
+ }
+
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ {
+ byte[] tmp = new byte[sigAlgParams.length];
+
+ System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" Version: ").append(this.getVersion()).append(
+ nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN())
+ .append(nl);
+ buf.append(" This update: ").append(this.getThisUpdate())
+ .append(nl);
+ buf.append(" Next update: ").append(this.getNextUpdate())
+ .append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName())
+ .append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(
+ new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: ").append(nl);
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(
+ ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.cRLNumber))
+ {
+ buf.append(
+ new CRLNumber(ASN1Integer.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid.equals(Extension.deltaCRLIndicator))
+ {
+ buf.append(
+ "Base CRL: "
+ + new CRLNumber(ASN1Integer.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid
+ .equals(Extension.issuingDistributionPoint))
+ {
+ buf.append(
+ IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid
+ .equals(Extension.cRLDistributionPoints))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.freshestCRL))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(
+ ASN1Dump.dumpAsString(dIn.readObject()))
+ .append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ Set set = getRevokedCertificates();
+ if (set != null)
+ {
+ Iterator it = set.iterator();
+ while (it.hasNext())
+ {
+ buf.append(it.next());
+ buf.append(nl);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!cert.getType().equals("X.509"))
+ {
+ throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+ }
+
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name caName = c.getIssuer();
+
+ if (certs != null)
+ {
+ BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement());
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+
+ if (entry.getUserCertificate().getValue().equals(serial))
+ {
+ X500Name issuer;
+
+ if (cert instanceof X509Certificate)
+ {
+ issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded());
+ }
+ else
+ {
+ try
+ {
+ issuer = org.spongycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new RuntimeException("Cannot process certificate");
+ }
+ }
+
+ if (!caName.equals(issuer))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (this == other)
+ {
+ return true;
+ }
+
+ if (!(other instanceof X509CRL))
+ {
+ return false;
+ }
+
+ if (other instanceof X509CRLObject)
+ {
+ X509CRLObject crlObject = (X509CRLObject)other;
+
+ if (isHashCodeSet)
+ {
+ boolean otherIsHashCodeSet = crlObject.isHashCodeSet;
+ if (otherIsHashCodeSet)
+ {
+ if (crlObject.hashCodeValue != hashCodeValue)
+ {
+ return false;
+ }
+ }
+ }
+
+ return this.c.equals(crlObject.c);
+ }
+
+ return super.equals(other);
+ }
+
+ public int hashCode()
+ {
+ if (!isHashCodeSet)
+ {
+ isHashCodeSet = true;
+ hashCodeValue = super.hashCode();
+ }
+
+ return hashCodeValue;
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLParser.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLParser.java
new file mode 100644
index 000000000..53aec7a32
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CRLParser.java
@@ -0,0 +1,150 @@
+package org.spongycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.x509.X509StreamParserSpi;
+import org.spongycastle.x509.util.StreamParsingException;
+
+public class X509CRLParser
+ extends X509StreamParserSpi
+{
+ private static final PEMUtil PEM_PARSER = new PEMUtil("CRL");
+
+ private ASN1Set sData = null;
+ private int sDataObjectCount = 0;
+ private InputStream currentStream = null;
+
+ private CRL readDERCRL(
+ InputStream in)
+ throws IOException, CRLException
+ {
+ ASN1InputStream dIn = new ASN1InputStream(in);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof DERObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sData = new SignedData(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
+
+ return getCRL();
+ }
+ }
+
+ return new X509CRLObject(CertificateList.getInstance(seq));
+ }
+
+ private CRL getCRL()
+ throws CRLException
+ {
+ if (sData == null || sDataObjectCount >= sData.size())
+ {
+ return null;
+ }
+
+ return new X509CRLObject(
+ CertificateList.getInstance(
+ sData.getObjectAt(sDataObjectCount++)));
+ }
+
+ private CRL readPEMCRL(
+ InputStream in)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = PEM_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return new X509CRLObject(CertificateList.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ public void engineInit(InputStream in)
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+
+ if (!currentStream.markSupported())
+ {
+ currentStream = new BufferedInputStream(currentStream);
+ }
+ }
+
+ public Object engineRead()
+ throws StreamParsingException
+ {
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.size())
+ {
+ return getCRL();
+ }
+ else
+ {
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ currentStream.mark(10);
+ int tag = currentStream.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ currentStream.reset();
+ return readPEMCRL(currentStream);
+ }
+ else
+ {
+ currentStream.reset();
+ return readDERCRL(currentStream);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new StreamParsingException(e.toString(), e);
+ }
+ }
+
+ public Collection engineReadAll()
+ throws StreamParsingException
+ {
+ CRL crl;
+ List certs = new ArrayList();
+
+ while ((crl = (CRL)engineRead()) != null)
+ {
+ certs.add(crl);
+ }
+
+ return certs;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertPairParser.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertPairParser.java
new file mode 100644
index 000000000..af106769e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertPairParser.java
@@ -0,0 +1,77 @@
+package org.spongycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CertificateParsingException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.x509.CertificatePair;
+import org.spongycastle.x509.X509CertificatePair;
+import org.spongycastle.x509.X509StreamParserSpi;
+import org.spongycastle.x509.util.StreamParsingException;
+
+public class X509CertPairParser
+ extends X509StreamParserSpi
+{
+ private InputStream currentStream = null;
+
+ private X509CertificatePair readDERCrossCertificatePair(
+ InputStream in)
+ throws IOException, CertificateParsingException
+ {
+ ASN1InputStream dIn = new ASN1InputStream(in);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ CertificatePair pair = CertificatePair.getInstance(seq);
+ return new X509CertificatePair(pair);
+ }
+
+ public void engineInit(InputStream in)
+ {
+ currentStream = in;
+
+ if (!currentStream.markSupported())
+ {
+ currentStream = new BufferedInputStream(currentStream);
+ }
+ }
+
+ public Object engineRead() throws StreamParsingException
+ {
+ try
+ {
+
+ currentStream.mark(10);
+ int tag = currentStream.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ currentStream.reset();
+ return readDERCrossCertificatePair(currentStream);
+ }
+ catch (Exception e)
+ {
+ throw new StreamParsingException(e.toString(), e);
+ }
+ }
+
+ public Collection engineReadAll() throws StreamParsingException
+ {
+ X509CertificatePair pair;
+ List certs = new ArrayList();
+
+ while ((pair = (X509CertificatePair)engineRead()) != null)
+ {
+ certs.add(pair);
+ }
+
+ return certs;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertParser.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertParser.java
new file mode 100644
index 000000000..cc6752980
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertParser.java
@@ -0,0 +1,158 @@
+package org.spongycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.x509.X509StreamParserSpi;
+import org.spongycastle.x509.util.StreamParsingException;
+
+public class X509CertParser
+ extends X509StreamParserSpi
+{
+ private static final PEMUtil PEM_PARSER = new PEMUtil("CERTIFICATE");
+
+ private ASN1Set sData = null;
+ private int sDataObjectCount = 0;
+ private InputStream currentStream = null;
+
+ private Certificate readDERCertificate(
+ InputStream in)
+ throws IOException, CertificateParsingException
+ {
+ ASN1InputStream dIn = new ASN1InputStream(in);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof DERObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sData = new SignedData(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+
+ return getCertificate();
+ }
+ }
+
+ return new X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate.getInstance(seq));
+ }
+
+ private Certificate getCertificate()
+ throws CertificateParsingException
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.size())
+ {
+ Object obj = sData.getObjectAt(sDataObjectCount++);
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate.getInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Certificate readPEMCertificate(
+ InputStream in)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = PEM_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return new X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ public void engineInit(InputStream in)
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+
+ if (!currentStream.markSupported())
+ {
+ currentStream = new BufferedInputStream(currentStream);
+ }
+ }
+
+ public Object engineRead()
+ throws StreamParsingException
+ {
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.size())
+ {
+ return getCertificate();
+ }
+ else
+ {
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ currentStream.mark(10);
+ int tag = currentStream.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ currentStream.reset();
+ return readPEMCertificate(currentStream);
+ }
+ else
+ {
+ currentStream.reset();
+ return readDERCertificate(currentStream);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new StreamParsingException(e.toString(), e);
+ }
+ }
+
+ public Collection engineReadAll()
+ throws StreamParsingException
+ {
+ Certificate cert;
+ List certs = new ArrayList();
+
+ while ((cert = (Certificate)engineRead()) != null)
+ {
+ certs.add(cert);
+ }
+
+ return certs;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertificateObject.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertificateObject.java
new file mode 100644
index 000000000..ff89d574b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509CertificateObject.java
@@ -0,0 +1,901 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.misc.NetscapeRevocationURL;
+import org.spongycastle.asn1.misc.VerisignCzagExtension;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.encoders.Hex;
+
+public class X509CertificateObject
+ extends X509Certificate
+ implements PKCS12BagAttributeCarrier
+{
+ private org.spongycastle.asn1.x509.Certificate c;
+ private BasicConstraints basicConstraints;
+ private boolean[] keyUsage;
+ private boolean hashValueSet;
+ private int hashValue;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ public X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate c)
+ throws CertificateParsingException
+ {
+ this.c = c;
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.19");
+
+ if (bytes != null)
+ {
+ basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.15");
+ if (bytes != null)
+ {
+ DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+ bytes = bits.getBytes();
+ int length = (bytes.length * 8) - bits.getPadBits();
+
+ keyUsage = new boolean[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+ keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility
+ {
+ throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+ }
+
+ if (date.getTime() < this.getNotBefore().getTime())
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getSerialNumber().getValue();
+ }
+
+ public Principal getIssuerDN()
+ {
+ try
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public X500Principal getIssuerX500Principal()
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(c.getIssuer());
+
+ return new X500Principal(bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Principal getSubjectDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+ }
+
+ public X500Principal getSubjectX500Principal()
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(c.getSubject());
+
+ return new X500Principal(bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Date getNotBefore()
+ {
+ return c.getStartDate().getDate();
+ }
+
+ public Date getNotAfter()
+ {
+ return c.getEndDate().getDate();
+ }
+
+ public byte[] getTBSCertificate()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ /**
+ * return a more "meaningful" representation for the signature algorithm used in
+ * the certficate.
+ */
+ public String getSigAlgName()
+ {
+ Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ if (prov != null)
+ {
+ String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ Provider[] provs = Security.getProviders();
+
+ //
+ // search every provider looking for a real algorithm
+ //
+ for (int i = 0; i != provs.length; i++)
+ {
+ String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ return this.getSigAlgOID();
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getSigAlgParams()
+ {
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ try
+ {
+ return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getIssuerUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getSubjectUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ return keyUsage;
+ }
+
+ public List getExtendedKeyUsage()
+ throws CertificateParsingException
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.37");
+
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension");
+ }
+ }
+
+ return null;
+ }
+
+ public int getBasicConstraints()
+ {
+ if (basicConstraints != null)
+ {
+ if (basicConstraints.isCA())
+ {
+ if (basicConstraints.getPathLenConstraint() == null)
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return basicConstraints.getPathLenConstraint().intValue();
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ public Collection getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+ }
+
+ public Collection getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getExtensionBytes(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+ if (ext != null)
+ {
+ return ext.getExtnValue().getOctets();
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (!ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ if (this.getVersion() == 3)
+ {
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ String oidId = oid.getId();
+
+ if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
+ || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
+ || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
+ || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
+ || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
+ || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
+ || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
+ {
+ continue;
+ }
+
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ try
+ {
+ return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ return null; // should never happen...
+ }
+ }
+
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof Certificate))
+ {
+ return false;
+ }
+
+ Certificate other = (Certificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public synchronized int hashCode()
+ {
+ if (!hashValueSet)
+ {
+ hashValue = calculateHashCode();
+ hashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ private int calculateHashCode()
+ {
+ try
+ {
+ int hashCode = 0;
+ byte[] certData = this.getEncoded();
+ for (int i = 1; i < certData.length; i++)
+ {
+ hashCode += certData[i] * i;
+ }
+ return hashCode;
+ }
+ catch (CertificateEncodingException e)
+ {
+ return 0;
+ }
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" [0] Version: ").append(this.getVersion()).append(nl);
+ buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl);
+ buf.append(" Start Date: ").append(this.getNotBefore()).append(nl);
+ buf.append(" Final Date: ").append(this.getNotAfter()).append(nl);
+ buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl);
+ buf.append(" Public Key: ").append(this.getPublicKey()).append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: \n");
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.basicConstraints))
+ {
+ buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.keyUsage))
+ {
+ buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+ {
+ buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+ {
+ buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+ {
+ buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ //buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public final void verify(
+ PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature;
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ try
+ {
+ signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ signature = Signature.getInstance(sigName);
+ }
+
+ checkSignature(key, signature);
+ }
+
+ public final void verify(
+ PublicKey key,
+ String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+ Signature signature = Signature.getInstance(sigName, sigProvider);
+
+ checkSignature(key, signature);
+ }
+
+ private void checkSignature(
+ PublicKey key,
+ Signature signature)
+ throws CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException
+ {
+ if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+ // TODO This should go after the initVerify?
+ X509SignatureUtil.setSignatureParameters(signature, params);
+
+ signature.initVerify(key);
+
+ signature.update(this.getTBSCertificate());
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new SignatureException("certificate does not verify with supplied key");
+ }
+ }
+
+ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+ {
+ return false;
+ }
+
+ if (id1.getParameters() == null)
+ {
+ if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (id2.getParameters() == null)
+ {
+ if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return id1.getParameters().equals(id2.getParameters());
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return null;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ list.add(Integers.valueOf(genName.getTagNo()));
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getEncoded());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+ final String addr;
+ try
+ {
+ addr = InetAddress.getByAddress(addrBytes).getHostAddress();
+ }
+ catch (UnknownHostException e)
+ {
+ continue;
+ }
+ list.add(addr);
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(Collections.unmodifiableList(list));
+ }
+ if (temp.size() == 0)
+ {
+ return null;
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java
new file mode 100644
index 000000000..3f629ecaf
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java
@@ -0,0 +1,477 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.x509.CertificatePair;
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+
+/**
+ *
+ * This is a general purpose implementation to get X.509 certificates and CRLs
+ * from a LDAP location.
+ * <p>
+ * At first a search is performed in the ldap*AttributeNames of the
+ * {@link org.spongycastle.jce.X509LDAPCertStoreParameters} with the given
+ * information of the subject (for all kind of certificates) or issuer (for
+ * CRLs), respectively, if a X509CertSelector is given with that details. For
+ * CRLs, CA certificates and cross certificates a coarse search is made only for
+ * entries with that content to get more possibly matchign results.
+ */
+public class X509LDAPCertStoreSpi
+ extends CertStoreSpi
+{
+ private X509LDAPCertStoreParameters params;
+
+ public X509LDAPCertStoreSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof X509LDAPCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException(
+ X509LDAPCertStoreSpi.class.getName() + ": parameter must be a " + X509LDAPCertStoreParameters.class.getName() + " object\n"
+ + params.toString());
+ }
+
+ this.params = (X509LDAPCertStoreParameters)params;
+ }
+
+ /**
+ * Initial Context Factory.
+ */
+ private static String LDAP_PROVIDER = "com.sun.jndi.ldap.LdapCtxFactory";
+
+ /**
+ * Processing referrals..
+ */
+ private static String REFERRALS_IGNORE = "ignore";
+
+ /**
+ * Security level to be used for LDAP connections.
+ */
+ private static final String SEARCH_SECURITY_LEVEL = "none";
+
+ /**
+ * Package Prefix for loading URL context factories.
+ */
+ private static final String URL_CONTEXT_PREFIX = "com.sun.jndi.url";
+
+ private DirContext connectLDAP() throws NamingException
+ {
+ Properties props = new Properties();
+ props.setProperty(Context.INITIAL_CONTEXT_FACTORY, LDAP_PROVIDER);
+ props.setProperty(Context.BATCHSIZE, "0");
+
+ props.setProperty(Context.PROVIDER_URL, params.getLdapURL());
+ props.setProperty(Context.URL_PKG_PREFIXES, URL_CONTEXT_PREFIX);
+ props.setProperty(Context.REFERRAL, REFERRALS_IGNORE);
+ props.setProperty(Context.SECURITY_AUTHENTICATION,
+ SEARCH_SECURITY_LEVEL);
+
+ DirContext ctx = new InitialDirContext(props);
+ return ctx;
+ }
+
+ private String parseDN(String subject, String subjectAttributeName)
+ {
+ String temp = subject;
+ int begin = temp.toLowerCase().indexOf(
+ subjectAttributeName.toLowerCase());
+ temp = temp.substring(begin + subjectAttributeName.length());
+ int end = temp.indexOf(',');
+ if (end == -1)
+ {
+ end = temp.length();
+ }
+ while (temp.charAt(end - 1) == '\\')
+ {
+ end = temp.indexOf(',', end + 1);
+ if (end == -1)
+ {
+ end = temp.length();
+ }
+ }
+ temp = temp.substring(0, end);
+ begin = temp.indexOf('=');
+ temp = temp.substring(begin + 1);
+ if (temp.charAt(0) == ' ')
+ {
+ temp = temp.substring(1);
+ }
+ if (temp.startsWith("\""))
+ {
+ temp = temp.substring(1);
+ }
+ if (temp.endsWith("\""))
+ {
+ temp = temp.substring(0, temp.length() - 1);
+ }
+ return temp;
+ }
+
+ public Collection engineGetCertificates(CertSelector selector)
+ throws CertStoreException
+ {
+ if (!(selector instanceof X509CertSelector))
+ {
+ throw new CertStoreException("selector is not a X509CertSelector");
+ }
+ X509CertSelector xselector = (X509CertSelector)selector;
+
+ Set certSet = new HashSet();
+
+ Set set = getEndCertificates(xselector);
+ set.addAll(getCACertificates(xselector));
+ set.addAll(getCrossCertificates(xselector));
+
+ Iterator it = set.iterator();
+
+ try
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509",
+ BouncyCastleProvider.PROVIDER_NAME);
+ while (it.hasNext())
+ {
+ byte[] bytes = (byte[])it.next();
+ if (bytes == null || bytes.length == 0)
+ {
+ continue;
+ }
+
+ List bytesList = new ArrayList();
+ bytesList.add(bytes);
+
+ try
+ {
+ CertificatePair pair = CertificatePair
+ .getInstance(new ASN1InputStream(bytes)
+ .readObject());
+ bytesList.clear();
+ if (pair.getForward() != null)
+ {
+ bytesList.add(pair.getForward().getEncoded());
+ }
+ if (pair.getReverse() != null)
+ {
+ bytesList.add(pair.getReverse().getEncoded());
+ }
+ }
+ catch (IOException e)
+ {
+
+ }
+ catch (IllegalArgumentException e)
+ {
+
+ }
+ for (Iterator it2 = bytesList.iterator(); it2.hasNext();)
+ {
+ ByteArrayInputStream bIn = new ByteArrayInputStream(
+ (byte[])it2.next());
+ try
+ {
+ Certificate cert = cf.generateCertificate(bIn);
+ // System.out.println(((X509Certificate)
+ // cert).getSubjectX500Principal());
+ if (xselector.match(cert))
+ {
+ certSet.add(cert);
+ }
+ }
+ catch (Exception e)
+ {
+
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertStoreException(
+ "certificate cannot be constructed from LDAP result: " + e);
+ }
+
+ return certSet;
+ }
+
+ private Set certSubjectSerialSearch(X509CertSelector xselector,
+ String[] attrs, String attrName, String subjectAttributeName)
+ throws CertStoreException
+ {
+ Set set = new HashSet();
+ try
+ {
+ if (xselector.getSubjectAsBytes() != null
+ || xselector.getSubjectAsString() != null
+ || xselector.getCertificate() != null)
+ {
+ String subject = null;
+ String serial = null;
+ if (xselector.getCertificate() != null)
+ {
+ subject = xselector.getCertificate()
+ .getSubjectX500Principal().getName("RFC1779");
+ serial = xselector.getCertificate().getSerialNumber()
+ .toString();
+ }
+ else
+ {
+ if (xselector.getSubjectAsBytes() != null)
+ {
+ subject = new X500Principal(xselector
+ .getSubjectAsBytes()).getName("RFC1779");
+ }
+ else
+ {
+ subject = xselector.getSubjectAsString();
+ }
+ }
+ String attrValue = parseDN(subject, subjectAttributeName);
+ set.addAll(search(attrName, "*" + attrValue + "*", attrs));
+ if (serial != null
+ && params.getSearchForSerialNumberIn() != null)
+ {
+ attrValue = serial;
+ attrName = params.getSearchForSerialNumberIn();
+ set.addAll(search(attrName, "*" + attrValue + "*", attrs));
+ }
+ }
+ else
+ {
+ set.addAll(search(attrName, "*", attrs));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CertStoreException("exception processing selector: " + e);
+ }
+
+ return set;
+ }
+
+ private Set getEndCertificates(X509CertSelector xselector)
+ throws CertStoreException
+ {
+ String[] attrs = {params.getUserCertificateAttribute()};
+ String attrName = params.getLdapUserCertificateAttributeName();
+ String subjectAttributeName = params.getUserCertificateSubjectAttributeName();
+
+ Set set = certSubjectSerialSearch(xselector, attrs, attrName,
+ subjectAttributeName);
+ return set;
+ }
+
+ private Set getCACertificates(X509CertSelector xselector)
+ throws CertStoreException
+ {
+ String[] attrs = {params.getCACertificateAttribute()};
+ String attrName = params.getLdapCACertificateAttributeName();
+ String subjectAttributeName = params
+ .getCACertificateSubjectAttributeName();
+ Set set = certSubjectSerialSearch(xselector, attrs, attrName,
+ subjectAttributeName);
+
+ if (set.isEmpty())
+ {
+ set.addAll(search(null, "*", attrs));
+ }
+
+ return set;
+ }
+
+ private Set getCrossCertificates(X509CertSelector xselector)
+ throws CertStoreException
+ {
+ String[] attrs = {params.getCrossCertificateAttribute()};
+ String attrName = params.getLdapCrossCertificateAttributeName();
+ String subjectAttributeName = params
+ .getCrossCertificateSubjectAttributeName();
+ Set set = certSubjectSerialSearch(xselector, attrs, attrName,
+ subjectAttributeName);
+
+ if (set.isEmpty())
+ {
+ set.addAll(search(null, "*", attrs));
+ }
+
+ return set;
+ }
+
+ public Collection engineGetCRLs(CRLSelector selector)
+ throws CertStoreException
+ {
+ String[] attrs = {params.getCertificateRevocationListAttribute()};
+ if (!(selector instanceof X509CRLSelector))
+ {
+ throw new CertStoreException("selector is not a X509CRLSelector");
+ }
+ X509CRLSelector xselector = (X509CRLSelector)selector;
+
+ Set crlSet = new HashSet();
+
+ String attrName = params.getLdapCertificateRevocationListAttributeName();
+ Set set = new HashSet();
+
+ if (xselector.getIssuerNames() != null)
+ {
+ for (Iterator it = xselector.getIssuerNames().iterator(); it
+ .hasNext();)
+ {
+ Object o = it.next();
+ String attrValue = null;
+ if (o instanceof String)
+ {
+ String issuerAttributeName = params
+ .getCertificateRevocationListIssuerAttributeName();
+ attrValue = parseDN((String)o, issuerAttributeName);
+ }
+ else
+ {
+ String issuerAttributeName = params
+ .getCertificateRevocationListIssuerAttributeName();
+ attrValue = parseDN(new X500Principal((byte[])o)
+ .getName("RFC1779"), issuerAttributeName);
+ }
+ set.addAll(search(attrName, "*" + attrValue + "*", attrs));
+ }
+ }
+ else
+ {
+ set.addAll(search(attrName, "*", attrs));
+ }
+ set.addAll(search(null, "*", attrs));
+ Iterator it = set.iterator();
+
+ try
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509",
+ BouncyCastleProvider.PROVIDER_NAME);
+ while (it.hasNext())
+ {
+ CRL crl = cf.generateCRL(new ByteArrayInputStream((byte[])it
+ .next()));
+ if (xselector.match(crl))
+ {
+ crlSet.add(crl);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertStoreException(
+ "CRL cannot be constructed from LDAP result " + e);
+ }
+
+ return crlSet;
+ }
+
+ /**
+ * Returns a Set of byte arrays with the certificate or CRL encodings.
+ *
+ * @param attributeName The attribute name to look for in the LDAP.
+ * @param attributeValue The value the attribute name must have.
+ * @param attrs The attributes in the LDAP which hold the certificate,
+ * certificate pair or CRL in a found entry.
+ * @return Set of byte arrays with the certificate encodings.
+ */
+ private Set search(String attributeName, String attributeValue,
+ String[] attrs) throws CertStoreException
+ {
+ String filter = attributeName + "=" + attributeValue;
+ if (attributeName == null)
+ {
+ filter = null;
+ }
+ DirContext ctx = null;
+ Set set = new HashSet();
+ try
+ {
+
+ ctx = connectLDAP();
+
+ SearchControls constraints = new SearchControls();
+ constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ constraints.setCountLimit(0);
+ for (int i = 0; i < attrs.length; i++)
+ {
+ String temp[] = new String[1];
+ temp[0] = attrs[i];
+ constraints.setReturningAttributes(temp);
+
+ String filter2 = "(&(" + filter + ")(" + temp[0] + "=*))";
+ if (filter == null)
+ {
+ filter2 = "(" + temp[0] + "=*)";
+ }
+ NamingEnumeration results = ctx.search(params.getBaseDN(),
+ filter2, constraints);
+ while (results.hasMoreElements())
+ {
+ SearchResult sr = (SearchResult)results.next();
+ // should only be one attribute in the attribute set with
+ // one
+ // attribute value as byte array
+ NamingEnumeration enumeration = ((Attribute)(sr
+ .getAttributes().getAll().next())).getAll();
+ while (enumeration.hasMore())
+ {
+ Object o = enumeration.next();
+ set.add(o);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertStoreException(
+ "Error getting results from LDAP directory " + e);
+
+ }
+ finally
+ {
+ try
+ {
+ if (null != ctx)
+ {
+ ctx.close();
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ return set;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509SignatureUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509SignatureUtil.java
new file mode 100644
index 000000000..030d52016
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509SignatureUtil.java
@@ -0,0 +1,138 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.PSSParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+class X509SignatureUtil
+{
+ private static final ASN1Null derNull = DERNull.INSTANCE;
+
+ static void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !derNull.equals(params))
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+
+ if (signature.getAlgorithm().endsWith("MGF1"))
+ {
+ try
+ {
+ signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ }
+ if (sigAlgId.getObjectId().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+ {
+ ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+
+ return getDigestAlgName((DERObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ DERObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreAttrCertCollection.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreAttrCertCollection.java
new file mode 100644
index 000000000..25102f35f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreAttrCertCollection.java
@@ -0,0 +1,34 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.X509CollectionStoreParameters;
+import org.spongycastle.x509.X509StoreParameters;
+import org.spongycastle.x509.X509StoreSpi;
+
+public class X509StoreAttrCertCollection
+ extends X509StoreSpi
+{
+ private CollectionStore _store;
+
+ public X509StoreAttrCertCollection()
+ {
+ }
+
+ public void engineInit(X509StoreParameters params)
+ {
+ if (!(params instanceof X509CollectionStoreParameters))
+ {
+ throw new IllegalArgumentException(params.toString());
+ }
+
+ _store = new CollectionStore(((X509CollectionStoreParameters)params).getCollection());
+ }
+
+ public Collection engineGetMatches(Selector selector)
+ {
+ return _store.getMatches(selector);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCRLCollection.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCRLCollection.java
new file mode 100644
index 000000000..46b75c23c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCRLCollection.java
@@ -0,0 +1,34 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.X509CollectionStoreParameters;
+import org.spongycastle.x509.X509StoreParameters;
+import org.spongycastle.x509.X509StoreSpi;
+
+public class X509StoreCRLCollection
+ extends X509StoreSpi
+{
+ private CollectionStore _store;
+
+ public X509StoreCRLCollection()
+ {
+ }
+
+ public void engineInit(X509StoreParameters params)
+ {
+ if (!(params instanceof X509CollectionStoreParameters))
+ {
+ throw new IllegalArgumentException(params.toString());
+ }
+
+ _store = new CollectionStore(((X509CollectionStoreParameters)params).getCollection());
+ }
+
+ public Collection engineGetMatches(Selector selector)
+ {
+ return _store.getMatches(selector);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCertCollection.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCertCollection.java
new file mode 100644
index 000000000..616de533e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCertCollection.java
@@ -0,0 +1,34 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.X509CollectionStoreParameters;
+import org.spongycastle.x509.X509StoreParameters;
+import org.spongycastle.x509.X509StoreSpi;
+
+public class X509StoreCertCollection
+ extends X509StoreSpi
+{
+ private CollectionStore _store;
+
+ public X509StoreCertCollection()
+ {
+ }
+
+ public void engineInit(X509StoreParameters params)
+ {
+ if (!(params instanceof X509CollectionStoreParameters))
+ {
+ throw new IllegalArgumentException(params.toString());
+ }
+
+ _store = new CollectionStore(((X509CollectionStoreParameters)params).getCollection());
+ }
+
+ public Collection engineGetMatches(Selector selector)
+ {
+ return _store.getMatches(selector);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCertPairCollection.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCertPairCollection.java
new file mode 100644
index 000000000..bd8f8ea88
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreCertPairCollection.java
@@ -0,0 +1,64 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+
+import org.spongycastle.util.CollectionStore;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.X509CollectionStoreParameters;
+import org.spongycastle.x509.X509StoreParameters;
+import org.spongycastle.x509.X509StoreSpi;
+
+/**
+ * This class is a collection based Bouncy Castle
+ * {@link org.spongycastle.x509.X509Store} SPI implementation for certificate
+ * pairs.
+ *
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.x509.X509CertificatePair
+ */
+public class X509StoreCertPairCollection extends X509StoreSpi
+{
+
+ private CollectionStore _store;
+
+ public X509StoreCertPairCollection()
+ {
+ }
+
+ /**
+ * Initializes this store.
+ *
+ * @param params The {@link X509CollectionStoreParameters}s for this store.
+ * @throws IllegalArgumentException if <code>params</code> is no instance of
+ * <code>X509CollectionStoreParameters</code>.
+ */
+ public void engineInit(X509StoreParameters params)
+ {
+ if (!(params instanceof X509CollectionStoreParameters))
+ {
+ throw new IllegalArgumentException(
+ "Initialization parameters must be an instance of "
+ + X509CollectionStoreParameters.class.getName()
+ + ".");
+ }
+
+ _store = new CollectionStore(((X509CollectionStoreParameters)params)
+ .getCollection());
+ }
+
+ /**
+ * Returns a colelction of certificate pairs which match the given
+ * <code>selector</code>.
+ * <p/>
+ * The returned collection contains
+ * {@link org.spongycastle.x509.X509CertificatePair}s. The selector must be
+ * a {@link org.spongycastle.x509.X509CertPairStoreSelector} to select
+ * certificate pairs.
+ *
+ * @return A collection with matching certificate pairs.
+ */
+ public Collection engineGetMatches(Selector selector)
+ {
+ return _store.getMatches(selector);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPAttrCerts.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPAttrCerts.java
new file mode 100644
index 000000000..45057c101
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPAttrCerts.java
@@ -0,0 +1,79 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509StoreParameters;
+import org.spongycastle.x509.X509StoreSpi;
+import org.spongycastle.x509.util.LDAPStoreHelper;
+
+/**
+ * A SPI implementation of Bouncy Castle <code>X509Store</code> for getting
+ * attribute certificates from an LDAP directory.
+ *
+ * @see org.spongycastle.x509.X509Store
+ */
+public class X509StoreLDAPAttrCerts extends X509StoreSpi
+{
+
+ private LDAPStoreHelper helper;
+
+ public X509StoreLDAPAttrCerts()
+ {
+ }
+
+ /**
+ * Initializes this LDAP attribute cert store implementation.
+ *
+ * @param parameters <code>X509LDAPCertStoreParameters</code>.
+ * @throws IllegalArgumentException if <code>params</code> is not an instance of
+ * <code>X509LDAPCertStoreParameters</code>.
+ */
+ public void engineInit(X509StoreParameters parameters)
+ {
+ if (!(parameters instanceof X509LDAPCertStoreParameters))
+ {
+ throw new IllegalArgumentException(
+ "Initialization parameters must be an instance of "
+ + X509LDAPCertStoreParameters.class.getName() + ".");
+ }
+ helper = new LDAPStoreHelper((X509LDAPCertStoreParameters)parameters);
+ }
+
+ /**
+ * Returns a collection of matching attribute certificates from the LDAP
+ * location.
+ * <p/>
+ * The selector must be a of type
+ * <code>X509AttributeCertStoreSelector</code>. If it is not an empty
+ * collection is returned.
+ * <p/>
+ * <p/>
+ * The subject and the serial number should be reasonable criterias for a
+ * selector.
+ *
+ * @param selector The selector to use for finding.
+ * @return A collection with the matches.
+ * @throws StoreException if an exception occurs while searching.
+ */
+ public Collection engineGetMatches(Selector selector) throws StoreException
+ {
+ if (!(selector instanceof X509AttributeCertStoreSelector))
+ {
+ return Collections.EMPTY_SET;
+ }
+ X509AttributeCertStoreSelector xselector = (X509AttributeCertStoreSelector)selector;
+ Set set = new HashSet();
+ set.addAll(helper.getAACertificates(xselector));
+ set.addAll(helper.getAttributeCertificateAttributes(xselector));
+ set.addAll(helper.getAttributeDescriptorCertificates(xselector));
+ return set;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCRLs.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCRLs.java
new file mode 100644
index 000000000..c16498e80
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCRLs.java
@@ -0,0 +1,87 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509StoreParameters;
+import org.spongycastle.x509.X509StoreSpi;
+import org.spongycastle.x509.util.LDAPStoreHelper;
+
+/**
+ * A SPI implementation of Bouncy Castle <code>X509Store</code> for getting
+ * certificate revocation lists from an LDAP directory.
+ *
+ * @see org.spongycastle.x509.X509Store
+ */
+public class X509StoreLDAPCRLs extends X509StoreSpi
+{
+
+ private LDAPStoreHelper helper;
+
+ public X509StoreLDAPCRLs()
+ {
+ }
+
+ /**
+ * Initializes this LDAP CRL store implementation.
+ *
+ * @param params <code>X509LDAPCertStoreParameters</code>.
+ * @throws IllegalArgumentException if <code>params</code> is not an instance of
+ * <code>X509LDAPCertStoreParameters</code>.
+ */
+ public void engineInit(X509StoreParameters params)
+ {
+ if (!(params instanceof X509LDAPCertStoreParameters))
+ {
+ throw new IllegalArgumentException(
+ "Initialization parameters must be an instance of "
+ + X509LDAPCertStoreParameters.class.getName() + ".");
+ }
+ helper = new LDAPStoreHelper((X509LDAPCertStoreParameters)params);
+ }
+
+ /**
+ * Returns a collection of matching CRLs from the LDAP location.
+ * <p/>
+ * The selector must be a of type <code>X509CRLStoreSelector</code>. If
+ * it is not an empty collection is returned.
+ * <p/>
+ * The issuer should be a reasonable criteria for a selector.
+ *
+ * @param selector The selector to use for finding.
+ * @return A collection with the matches.
+ * @throws StoreException if an exception occurs while searching.
+ */
+ public Collection engineGetMatches(Selector selector) throws StoreException
+ {
+ if (!(selector instanceof X509CRLStoreSelector))
+ {
+ return Collections.EMPTY_SET;
+ }
+ X509CRLStoreSelector xselector = (X509CRLStoreSelector)selector;
+ Set set = new HashSet();
+ // test only delta CRLs should be selected
+ if (xselector.isDeltaCRLIndicatorEnabled())
+ {
+ set.addAll(helper.getDeltaCertificateRevocationLists(xselector));
+ }
+ // nothing specified
+ else
+ {
+ set.addAll(helper.getDeltaCertificateRevocationLists(xselector));
+ set.addAll(helper.getAttributeAuthorityRevocationLists(xselector));
+ set
+ .addAll(helper
+ .getAttributeCertificateRevocationLists(xselector));
+ set.addAll(helper.getAuthorityRevocationLists(xselector));
+ set.addAll(helper.getCertificateRevocationLists(xselector));
+ }
+ return set;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCertPairs.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCertPairs.java
new file mode 100644
index 000000000..8def97257
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCertPairs.java
@@ -0,0 +1,75 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.X509CertPairStoreSelector;
+import org.spongycastle.x509.X509StoreParameters;
+import org.spongycastle.x509.X509StoreSpi;
+import org.spongycastle.x509.util.LDAPStoreHelper;
+
+/**
+ * A SPI implementation of Bouncy Castle <code>X509Store</code> for getting
+ * cross certificates pairs from an LDAP directory.
+ *
+ * @see org.spongycastle.x509.X509Store
+ */
+public class X509StoreLDAPCertPairs extends X509StoreSpi
+{
+
+ private LDAPStoreHelper helper;
+
+ public X509StoreLDAPCertPairs()
+ {
+ }
+
+ /**
+ * Initializes this LDAP cross certificate pair store implementation.
+ *
+ * @param parameters <code>X509LDAPCertStoreParameters</code>.
+ * @throws IllegalArgumentException if <code>params</code> is not an instance of
+ * <code>X509LDAPCertStoreParameters</code>.
+ */
+ public void engineInit(X509StoreParameters parameters)
+ {
+ if (!(parameters instanceof X509LDAPCertStoreParameters))
+ {
+ throw new IllegalArgumentException(
+ "Initialization parameters must be an instance of "
+ + X509LDAPCertStoreParameters.class.getName() + ".");
+ }
+ helper = new LDAPStoreHelper((X509LDAPCertStoreParameters)parameters);
+ }
+
+ /**
+ * Returns a collection of matching cross certificate pairs from the LDAP
+ * location.
+ * <p/>
+ * The selector must be a of type <code>X509CertPairStoreSelector</code>.
+ * If it is not an empty collection is returned.
+ * <p/>
+ * <p/>
+ * The subject should be a reasonable criteria for a selector.
+ *
+ * @param selector The selector to use for finding.
+ * @return A collection with the matches.
+ * @throws StoreException if an exception occurs while searching.
+ */
+ public Collection engineGetMatches(Selector selector) throws StoreException
+ {
+ if (!(selector instanceof X509CertPairStoreSelector))
+ {
+ return Collections.EMPTY_SET;
+ }
+ X509CertPairStoreSelector xselector = (X509CertPairStoreSelector)selector;
+ Set set = new HashSet();
+ set.addAll(helper.getCrossCertificatePairs(xselector));
+ return set;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCerts.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCerts.java
new file mode 100644
index 000000000..ac6ea191f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/X509StoreLDAPCerts.java
@@ -0,0 +1,128 @@
+package org.spongycastle.jce.provider;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.X509CertPairStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+import org.spongycastle.x509.X509CertificatePair;
+import org.spongycastle.x509.X509StoreParameters;
+import org.spongycastle.x509.X509StoreSpi;
+import org.spongycastle.x509.util.LDAPStoreHelper;
+
+/**
+ * A SPI implementation of Bouncy Castle <code>X509Store</code> for getting
+ * certificates form a LDAP directory.
+ *
+ * @see org.spongycastle.x509.X509Store
+ */
+public class X509StoreLDAPCerts
+ extends X509StoreSpi
+{
+
+ private LDAPStoreHelper helper;
+
+ public X509StoreLDAPCerts()
+ {
+ }
+
+ /**
+ * Initializes this LDAP cert store implementation.
+ *
+ * @param params <code>X509LDAPCertStoreParameters</code>.
+ * @throws IllegalArgumentException if <code>params</code> is not an instance of
+ * <code>X509LDAPCertStoreParameters</code>.
+ */
+ public void engineInit(X509StoreParameters params)
+ {
+ if (!(params instanceof X509LDAPCertStoreParameters))
+ {
+ throw new IllegalArgumentException(
+ "Initialization parameters must be an instance of "
+ + X509LDAPCertStoreParameters.class.getName() + ".");
+ }
+ helper = new LDAPStoreHelper((X509LDAPCertStoreParameters)params);
+ }
+
+ /**
+ * Returns a collection of matching certificates from the LDAP location.
+ * <p/>
+ * The selector must be a of type <code>X509CertStoreSelector</code>. If
+ * it is not an empty collection is returned.
+ * <p/>
+ * The implementation searches only for CA certificates, if the method
+ * {@link java.security.cert.X509CertSelector#getBasicConstraints()} is
+ * greater or equal to 0. If it is -2 only end certificates are searched.
+ * <p/>
+ * The subject and the serial number for end certificates should be
+ * reasonable criterias for a selector.
+ *
+ * @param selector The selector to use for finding.
+ * @return A collection with the matches.
+ * @throws StoreException if an exception occurs while searching.
+ */
+ public Collection engineGetMatches(Selector selector) throws StoreException
+ {
+ if (!(selector instanceof X509CertStoreSelector))
+ {
+ return Collections.EMPTY_SET;
+ }
+ X509CertStoreSelector xselector = (X509CertStoreSelector)selector;
+ Set set = new HashSet();
+ // test if only CA certificates should be selected
+ if (xselector.getBasicConstraints() > 0)
+ {
+ set.addAll(helper.getCACertificates(xselector));
+ set.addAll(getCertificatesFromCrossCertificatePairs(xselector));
+ }
+ // only end certificates should be selected
+ else if (xselector.getBasicConstraints() == -2)
+ {
+ set.addAll(helper.getUserCertificates(xselector));
+ }
+ // nothing specified
+ else
+ {
+ set.addAll(helper.getUserCertificates(xselector));
+ set.addAll(helper.getCACertificates(xselector));
+ set.addAll(getCertificatesFromCrossCertificatePairs(xselector));
+ }
+ return set;
+ }
+
+ private Collection getCertificatesFromCrossCertificatePairs(
+ X509CertStoreSelector xselector) throws StoreException
+ {
+ Set set = new HashSet();
+ X509CertPairStoreSelector ps = new X509CertPairStoreSelector();
+
+ ps.setForwardSelector(xselector);
+ ps.setReverseSelector(new X509CertStoreSelector());
+
+ Set crossCerts = new HashSet(helper.getCrossCertificatePairs(ps));
+ Set forward = new HashSet();
+ Set reverse = new HashSet();
+ Iterator it = crossCerts.iterator();
+ while (it.hasNext())
+ {
+ X509CertificatePair pair = (X509CertificatePair)it.next();
+ if (pair.getForward() != null)
+ {
+ forward.add(pair.getForward());
+ }
+ if (pair.getReverse() != null)
+ {
+ reverse.add(pair.getReverse());
+ }
+ }
+ set.addAll(forward);
+ set.addAll(reverse);
+ return set;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECKeySpec.java
new file mode 100644
index 000000000..42ff1db32
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECKeySpec.java
@@ -0,0 +1,26 @@
+package org.spongycastle.jce.spec;
+
+import java.security.spec.KeySpec;
+
+/**
+ * base class for an Elliptic Curve Key Spec
+ */
+public class ECKeySpec
+ implements KeySpec
+{
+ private ECParameterSpec spec;
+
+ protected ECKeySpec(
+ ECParameterSpec spec)
+ {
+ this.spec = spec;
+ }
+
+ /**
+ * return the domain parameters for the curve
+ */
+ public ECParameterSpec getParams()
+ {
+ return spec;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveGenParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveGenParameterSpec.java
new file mode 100644
index 000000000..2b1d04041
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveGenParameterSpec.java
@@ -0,0 +1,28 @@
+package org.spongycastle.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Named curve generation spec
+ * <p>
+ * If you are using JDK 1.5 you should be looking at ECGenParameterSpec.
+ */
+public class ECNamedCurveGenParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private String name;
+
+ public ECNamedCurveGenParameterSpec(
+ String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * return the name of the curve the EC domain parameters belong to.
+ */
+ public String getName()
+ {
+ return name;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveParameterSpec.java
new file mode 100644
index 000000000..e7ef6c20b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveParameterSpec.java
@@ -0,0 +1,62 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+/**
+ * specification signifying that the curve parameters can also be
+ * refered to by name.
+ * <p>
+ * If you are using JDK 1.5 you should be looking at ECNamedCurveSpec.
+ */
+public class ECNamedCurveParameterSpec
+ extends ECParameterSpec
+{
+ private String name;
+
+ public ECNamedCurveParameterSpec(
+ String name,
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n)
+ {
+ super(curve, G, n);
+
+ this.name = name;
+ }
+
+ public ECNamedCurveParameterSpec(
+ String name,
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h)
+ {
+ super(curve, G, n, h);
+
+ this.name = name;
+ }
+
+ public ECNamedCurveParameterSpec(
+ String name,
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ super(curve, G, n, h, seed);
+
+ this.name = name;
+ }
+
+ /**
+ * return the name of the curve the EC domain parameters belong to.
+ */
+ public String getName()
+ {
+ return name;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveSpec.java
new file mode 100644
index 000000000..68b64a2a0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECNamedCurveSpec.java
@@ -0,0 +1,122 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+import org.spongycastle.math.ec.ECCurve;
+
+/**
+ * specification signifying that the curve parameters can also be
+ * referred to by name.
+ */
+public class ECNamedCurveSpec
+ extends java.security.spec.ECParameterSpec
+{
+ private String name;
+
+ private static EllipticCurve convertCurve(
+ ECCurve curve,
+ byte[] seed)
+ {
+ if (curve instanceof ECCurve.Fp)
+ {
+ return new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed);
+ }
+ else
+ {
+ ECCurve.F2m curveF2m = (ECCurve.F2m)curve;
+ int ks[];
+
+ if (curveF2m.isTrinomial())
+ {
+ ks = new int[] { curveF2m.getK1() };
+
+ return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed);
+ }
+ else
+ {
+ ks = new int[] { curveF2m.getK3(), curveF2m.getK2(), curveF2m.getK1() };
+
+ return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed);
+ }
+ }
+
+ }
+
+ private static ECPoint convertPoint(
+ org.spongycastle.math.ec.ECPoint g)
+ {
+ g = g.normalize();
+ return new ECPoint(g.getAffineXCoord().toBigInteger(), g.getAffineYCoord().toBigInteger());
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ ECCurve curve,
+ org.spongycastle.math.ec.ECPoint g,
+ BigInteger n)
+ {
+ super(convertCurve(curve, null), convertPoint(g), n, 1);
+
+ this.name = name;
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ EllipticCurve curve,
+ ECPoint g,
+ BigInteger n)
+ {
+ super(curve, g, n, 1);
+
+ this.name = name;
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ ECCurve curve,
+ org.spongycastle.math.ec.ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ {
+ super(convertCurve(curve, null), convertPoint(g), n, h.intValue());
+
+ this.name = name;
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ EllipticCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ {
+ super(curve, g, n, h.intValue());
+
+ this.name = name;
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ ECCurve curve,
+ org.spongycastle.math.ec.ECPoint g,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ super(convertCurve(curve, seed), convertPoint(g), n, h.intValue());
+
+ this.name = name;
+ }
+
+ /**
+ * return the name of the curve the EC domain parameters belong to.
+ */
+ public String getName()
+ {
+ return name;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECParameterSpec.java
new file mode 100644
index 000000000..f0f00e8c4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECParameterSpec.java
@@ -0,0 +1,121 @@
+package org.spongycastle.jce.spec;
+
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * basic domain parameters for an Elliptic Curve public or private key.
+ */
+public class ECParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private ECCurve curve;
+ private byte[] seed;
+ private ECPoint G;
+ private BigInteger n;
+ private BigInteger h;
+
+ public ECParameterSpec(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n)
+ {
+ this.curve = curve;
+ this.G = G.normalize();
+ this.n = n;
+ this.h = BigInteger.valueOf(1);
+ this.seed = null;
+ }
+
+ public ECParameterSpec(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h)
+ {
+ this.curve = curve;
+ this.G = G.normalize();
+ this.n = n;
+ this.h = h;
+ this.seed = null;
+ }
+
+ public ECParameterSpec(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ this.curve = curve;
+ this.G = G.normalize();
+ this.n = n;
+ this.h = h;
+ this.seed = seed;
+ }
+
+ /**
+ * return the curve along which the base point lies.
+ * @return the curve
+ */
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ /**
+ * return the base point we are using for these domain parameters.
+ * @return the base point.
+ */
+ public ECPoint getG()
+ {
+ return G;
+ }
+
+ /**
+ * return the order N of G
+ * @return the order
+ */
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ /**
+ * return the cofactor H to the order of G.
+ * @return the cofactor
+ */
+ public BigInteger getH()
+ {
+ return h;
+ }
+
+ /**
+ * return the seed used to generate this curve (if available).
+ * @return the random seed
+ */
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof ECParameterSpec))
+ {
+ return false;
+ }
+
+ ECParameterSpec other = (ECParameterSpec)o;
+
+ return this.getCurve().equals(other.getCurve()) && this.getG().equals(other.getG());
+ }
+
+ public int hashCode()
+ {
+ return this.getCurve().hashCode() ^ this.getG().hashCode();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECPrivateKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECPrivateKeySpec.java
new file mode 100644
index 000000000..36b0db123
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECPrivateKeySpec.java
@@ -0,0 +1,35 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+
+/**
+ * Elliptic Curve private key specification.
+ */
+public class ECPrivateKeySpec
+ extends ECKeySpec
+{
+ private BigInteger d;
+
+ /**
+ * base constructor
+ *
+ * @param d the private number for the key.
+ * @param spec the domain parameters for the curve being used.
+ */
+ public ECPrivateKeySpec(
+ BigInteger d,
+ ECParameterSpec spec)
+ {
+ super(spec);
+
+ this.d = d;
+ }
+
+ /**
+ * return the private number D
+ */
+ public BigInteger getD()
+ {
+ return d;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECPublicKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECPublicKeySpec.java
new file mode 100644
index 000000000..e2888d387
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ECPublicKeySpec.java
@@ -0,0 +1,42 @@
+package org.spongycastle.jce.spec;
+
+import org.spongycastle.math.ec.ECPoint;
+
+/**
+ * Elliptic Curve public key specification
+ */
+public class ECPublicKeySpec
+ extends ECKeySpec
+{
+ private ECPoint q;
+
+ /**
+ * base constructor
+ *
+ * @param q the public point on the curve.
+ * @param spec the domain parameters for the curve.
+ */
+ public ECPublicKeySpec(
+ ECPoint q,
+ ECParameterSpec spec)
+ {
+ super(spec);
+
+ if (q.getCurve() != null)
+ {
+ this.q = q.normalize();
+ }
+ else
+ {
+ this.q = q;
+ }
+ }
+
+ /**
+ * return the public point q
+ */
+ public ECPoint getQ()
+ {
+ return q;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalGenParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalGenParameterSpec.java
new file mode 100644
index 000000000..3e45484d2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalGenParameterSpec.java
@@ -0,0 +1,28 @@
+package org.spongycastle.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+public class ElGamalGenParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private int primeSize;
+
+ /*
+ * @param primeSize the size (in bits) of the prime modulus.
+ */
+ public ElGamalGenParameterSpec(
+ int primeSize)
+ {
+ this.primeSize = primeSize;
+ }
+
+ /**
+ * Returns the size in bits of the prime modulus.
+ *
+ * @return the size in bits of the prime modulus
+ */
+ public int getPrimeSize()
+ {
+ return primeSize;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalKeySpec.java
new file mode 100644
index 000000000..49d3f2f0d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalKeySpec.java
@@ -0,0 +1,20 @@
+package org.spongycastle.jce.spec;
+
+import java.security.spec.KeySpec;
+
+public class ElGamalKeySpec
+ implements KeySpec
+{
+ private ElGamalParameterSpec spec;
+
+ public ElGamalKeySpec(
+ ElGamalParameterSpec spec)
+ {
+ this.spec = spec;
+ }
+
+ public ElGamalParameterSpec getParams()
+ {
+ return spec;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalParameterSpec.java
new file mode 100644
index 000000000..276790f86
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalParameterSpec.java
@@ -0,0 +1,46 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+public class ElGamalParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private BigInteger p;
+ private BigInteger g;
+
+ /**
+ * Constructs a parameter set for Diffie-Hellman, using a prime modulus
+ * <code>p</code> and a base generator <code>g</code>.
+ *
+ * @param p the prime modulus
+ * @param g the base generator
+ */
+ public ElGamalParameterSpec(
+ BigInteger p,
+ BigInteger g)
+ {
+ this.p = p;
+ this.g = g;
+ }
+
+ /**
+ * Returns the prime modulus <code>p</code>.
+ *
+ * @return the prime modulus <code>p</code>
+ */
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ /**
+ * Returns the base generator <code>g</code>.
+ *
+ * @return the base generator <code>g</code>
+ */
+ public BigInteger getG()
+ {
+ return g;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalPrivateKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalPrivateKeySpec.java
new file mode 100644
index 000000000..be023e341
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalPrivateKeySpec.java
@@ -0,0 +1,33 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies an ElGamal private key with its associated parameters.
+ *
+ * @see ElGamalPublicKeySpec
+ */
+public class ElGamalPrivateKeySpec
+ extends ElGamalKeySpec
+{
+ private BigInteger x;
+
+ public ElGamalPrivateKeySpec(
+ BigInteger x,
+ ElGamalParameterSpec spec)
+ {
+ super(spec);
+
+ this.x = x;
+ }
+
+ /**
+ * Returns the private value <code>x</code>.
+ *
+ * @return the private value <code>x</code>
+ */
+ public BigInteger getX()
+ {
+ return x;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalPublicKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalPublicKeySpec.java
new file mode 100644
index 000000000..558730e5b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/ElGamalPublicKeySpec.java
@@ -0,0 +1,33 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies an ElGamal public key with its associated parameters.
+ *
+ * @see ElGamalPrivateKeySpec
+ */
+public class ElGamalPublicKeySpec
+ extends ElGamalKeySpec
+{
+ private BigInteger y;
+
+ public ElGamalPublicKeySpec(
+ BigInteger y,
+ ElGamalParameterSpec spec)
+ {
+ super(spec);
+
+ this.y = y;
+ }
+
+ /**
+ * Returns the public value <code>y</code>.
+ *
+ * @return the public value <code>y</code>
+ */
+ public BigInteger getY()
+ {
+ return y;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST28147ParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST28147ParameterSpec.java
new file mode 100644
index 000000000..a721db931
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST28147ParameterSpec.java
@@ -0,0 +1,48 @@
+package org.spongycastle.jce.spec;
+
+/**
+ * A parameter spec for the GOST-28147 cipher.
+ * @deprecated use org.spongycastle.jcajce.spec.GOST28147ParameterSpec
+ */
+public class GOST28147ParameterSpec
+ extends org.spongycastle.jcajce.spec.GOST28147ParameterSpec
+{
+ /**
+ * @deprecated
+ */
+ public GOST28147ParameterSpec(
+ byte[] sBox)
+ {
+ super(sBox);
+ }
+
+ /**
+ * @deprecated
+ */
+ public GOST28147ParameterSpec(
+ byte[] sBox,
+ byte[] iv)
+ {
+ super(sBox, iv);
+
+ }
+
+ /**
+ * @deprecated
+ */
+ public GOST28147ParameterSpec(
+ String sBoxName)
+ {
+ super(sBoxName);
+ }
+
+ /**
+ * @deprecated
+ */
+ public GOST28147ParameterSpec(
+ String sBoxName,
+ byte[] iv)
+ {
+ super(sBoxName, iv);
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410ParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410ParameterSpec.java
new file mode 100644
index 000000000..755a52846
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410ParameterSpec.java
@@ -0,0 +1,133 @@
+package org.spongycastle.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.GOST3410NamedParameters;
+import org.spongycastle.asn1.cryptopro.GOST3410ParamSetParameters;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import org.spongycastle.jce.interfaces.GOST3410Params;
+
+/**
+ * ParameterSpec for a GOST 3410-94 key.
+ */
+public class GOST3410ParameterSpec
+ implements AlgorithmParameterSpec, GOST3410Params
+{
+ private GOST3410PublicKeyParameterSetSpec keyParameters;
+ private String keyParamSetOID;
+ private String digestParamSetOID;
+ private String encryptionParamSetOID;
+
+ public GOST3410ParameterSpec(
+ String keyParamSetID,
+ String digestParamSetOID,
+ String encryptionParamSetOID)
+ {
+ GOST3410ParamSetParameters ecP = null;
+
+ try
+ {
+ ecP = GOST3410NamedParameters.getByOID(new ASN1ObjectIdentifier(keyParamSetID));
+ }
+ catch (IllegalArgumentException e)
+ {
+ ASN1ObjectIdentifier oid = GOST3410NamedParameters.getOID(keyParamSetID);
+ if (oid != null)
+ {
+ keyParamSetID = oid.getId();
+ ecP = GOST3410NamedParameters.getByOID(oid);
+ }
+ }
+
+ if (ecP == null)
+ {
+ throw new IllegalArgumentException("no key parameter set for passed in name/OID.");
+ }
+
+ this.keyParameters = new GOST3410PublicKeyParameterSetSpec(
+ ecP.getP(),
+ ecP.getQ(),
+ ecP.getA());
+
+ this.keyParamSetOID = keyParamSetID;
+ this.digestParamSetOID = digestParamSetOID;
+ this.encryptionParamSetOID = encryptionParamSetOID;
+ }
+
+ public GOST3410ParameterSpec(
+ String keyParamSetID,
+ String digestParamSetOID)
+ {
+ this(keyParamSetID, digestParamSetOID, null);
+ }
+
+ public GOST3410ParameterSpec(
+ String keyParamSetID)
+ {
+ this(keyParamSetID, CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet.getId(), null);
+ }
+
+ public GOST3410ParameterSpec(
+ GOST3410PublicKeyParameterSetSpec spec)
+ {
+ this.keyParameters = spec;
+ this.digestParamSetOID = CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet.getId();
+ this.encryptionParamSetOID = null;
+ }
+
+ public String getPublicKeyParamSetOID()
+ {
+ return this.keyParamSetOID;
+ }
+
+ public GOST3410PublicKeyParameterSetSpec getPublicKeyParameters()
+ {
+ return keyParameters;
+ }
+
+ public String getDigestParamSetOID()
+ {
+ return this.digestParamSetOID;
+ }
+
+ public String getEncryptionParamSetOID()
+ {
+ return this.encryptionParamSetOID;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o instanceof GOST3410ParameterSpec)
+ {
+ GOST3410ParameterSpec other = (GOST3410ParameterSpec)o;
+
+ return this.keyParameters.equals(other.keyParameters)
+ && this.digestParamSetOID.equals(other.digestParamSetOID)
+ && (this.encryptionParamSetOID == other.encryptionParamSetOID
+ || (this.encryptionParamSetOID != null && this.encryptionParamSetOID.equals(other.encryptionParamSetOID)));
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return this.keyParameters.hashCode() ^ this.digestParamSetOID.hashCode()
+ ^ (this.encryptionParamSetOID != null ? this.encryptionParamSetOID.hashCode() : 0);
+ }
+
+ public static GOST3410ParameterSpec fromPublicKeyAlg(
+ GOST3410PublicKeyAlgParameters params)
+ {
+ if (params.getEncryptionParamSet() != null)
+ {
+ return new GOST3410ParameterSpec(params.getPublicKeyParamSet().getId(), params.getDigestParamSet().getId(), params.getEncryptionParamSet().getId());
+ }
+ else
+ {
+ return new GOST3410ParameterSpec(params.getPublicKeyParamSet().getId(), params.getDigestParamSet().getId());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PrivateKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PrivateKeySpec.java
new file mode 100644
index 000000000..428221461
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PrivateKeySpec.java
@@ -0,0 +1,70 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+import java.security.spec.KeySpec;
+
+/**
+ * This class specifies a GOST3410-94 private key with its associated parameters.
+ */
+
+public class GOST3410PrivateKeySpec
+ implements KeySpec
+{
+ private BigInteger x;
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger a;
+
+ /**
+ * Creates a new GOST3410PrivateKeySpec with the specified parameter values.
+ *
+ * @param x the private key.
+ * @param p the prime.
+ * @param q the sub-prime.
+ * @param a the base.
+ */
+ public GOST3410PrivateKeySpec(BigInteger x, BigInteger p, BigInteger q,
+ BigInteger a)
+ {
+ this.x = x;
+ this.p = p;
+ this.q = q;
+ this.a = a;
+ }
+
+ /**
+ * Returns the private key <code>x</code>.
+ * @return the private key <code>x</code>.
+ */
+ public BigInteger getX()
+ {
+ return this.x;
+ }
+
+ /**
+ * Returns the prime <code>p</code>.
+ * @return the prime <code>p</code>.
+ */
+ public BigInteger getP()
+ {
+ return this.p;
+ }
+
+ /**
+ * Returns the sub-prime <code>q</code>.
+ * @return the sub-prime <code>q</code>.
+ */
+ public BigInteger getQ()
+ {
+ return this.q;
+ }
+
+ /**
+ * Returns the base <code>a</code>.
+ * @return the base <code>a</code>.
+ */
+ public BigInteger getA()
+ {
+ return this.a;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PublicKeyParameterSetSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PublicKeyParameterSetSpec.java
new file mode 100644
index 000000000..0b7af57e6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PublicKeyParameterSetSpec.java
@@ -0,0 +1,78 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+
+/**
+ * ParameterSpec for a GOST 3410-94 key parameters.
+ */
+public class GOST3410PublicKeyParameterSetSpec
+{
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger a;
+
+ /**
+ * Creates a new GOST3410ParameterSpec with the specified parameter values.
+ *
+ * @param p the prime.
+ * @param q the sub-prime.
+ * @param a the base.
+ */
+ public GOST3410PublicKeyParameterSetSpec(
+ BigInteger p,
+ BigInteger q,
+ BigInteger a)
+ {
+ this.p = p;
+ this.q = q;
+ this.a = a;
+ }
+
+ /**
+ * Returns the prime <code>p</code>.
+ *
+ * @return the prime <code>p</code>.
+ */
+ public BigInteger getP()
+ {
+ return this.p;
+ }
+
+ /**
+ * Returns the sub-prime <code>q</code>.
+ *
+ * @return the sub-prime <code>q</code>.
+ */
+ public BigInteger getQ()
+ {
+ return this.q;
+ }
+
+ /**
+ * Returns the base <code>a</code>.
+ *
+ * @return the base <code>a</code>.
+ */
+ public BigInteger getA()
+ {
+ return this.a;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o instanceof GOST3410PublicKeyParameterSetSpec)
+ {
+ GOST3410PublicKeyParameterSetSpec other = (GOST3410PublicKeyParameterSetSpec)o;
+
+ return this.a.equals(other.a) && this.p.equals(other.p) && this.q.equals(other.q);
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return a.hashCode() ^ p.hashCode() ^ q.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PublicKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PublicKeySpec.java
new file mode 100644
index 000000000..a16d36ce9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/GOST3410PublicKeySpec.java
@@ -0,0 +1,78 @@
+package org.spongycastle.jce.spec;
+
+import java.math.BigInteger;
+import java.security.spec.KeySpec;
+
+/**
+ * This class specifies a GOST3410-94 public key with its associated parameters.
+ */
+
+public class GOST3410PublicKeySpec
+ implements KeySpec
+{
+
+ private BigInteger y;
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger a;
+
+ /**
+ * Creates a new GOST3410PublicKeySpec with the specified parameter values.
+ *
+ * @param y the public key.
+ * @param p the prime.
+ * @param q the sub-prime.
+ * @param a the base.
+ */
+ public GOST3410PublicKeySpec(
+ BigInteger y,
+ BigInteger p,
+ BigInteger q,
+ BigInteger a)
+ {
+ this.y = y;
+ this.p = p;
+ this.q = q;
+ this.a = a;
+ }
+
+ /**
+ * Returns the public key <code>y</code>.
+ *
+ * @return the public key <code>y</code>.
+ */
+ public BigInteger getY()
+ {
+ return this.y;
+ }
+
+ /**
+ * Returns the prime <code>p</code>.
+ *
+ * @return the prime <code>p</code>.
+ */
+ public BigInteger getP()
+ {
+ return this.p;
+ }
+
+ /**
+ * Returns the sub-prime <code>q</code>.
+ *
+ * @return the sub-prime <code>q</code>.
+ */
+ public BigInteger getQ()
+ {
+ return this.q;
+ }
+
+ /**
+ * Returns the base <code>g</code>.
+ *
+ * @return the base <code>g</code>.
+ */
+ public BigInteger getA()
+ {
+ return this.a;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/IEKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/IEKeySpec.java
new file mode 100644
index 000000000..050760f7c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/IEKeySpec.java
@@ -0,0 +1,70 @@
+package org.spongycastle.jce.spec;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.jce.interfaces.IESKey;
+
+/**
+ * key pair for use with an integrated encryptor - together
+ * they provide what's required to generate the message.
+ */
+public class IEKeySpec
+ implements KeySpec, IESKey
+{
+ private PublicKey pubKey;
+ private PrivateKey privKey;
+
+ /**
+ * @param privKey our private key.
+ * @param pubKey the public key of the sender/recipient.
+ */
+ public IEKeySpec(
+ PrivateKey privKey,
+ PublicKey pubKey)
+ {
+ this.privKey = privKey;
+ this.pubKey = pubKey;
+ }
+
+ /**
+ * return the intended recipient's/sender's public key.
+ */
+ public PublicKey getPublic()
+ {
+ return pubKey;
+ }
+
+ /**
+ * return the local private key.
+ */
+ public PrivateKey getPrivate()
+ {
+ return privKey;
+ }
+
+ /**
+ * return "IES"
+ */
+ public String getAlgorithm()
+ {
+ return "IES";
+ }
+
+ /**
+ * return null
+ */
+ public String getFormat()
+ {
+ return null;
+ }
+
+ /**
+ * returns null
+ */
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/IESParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/IESParameterSpec.java
new file mode 100644
index 000000000..e590a7690
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/IESParameterSpec.java
@@ -0,0 +1,104 @@
+package org.spongycastle.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Parameter spec for an integrated encryptor, as in IEEE P1363a
+ */
+public class IESParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private byte[] derivation;
+ private byte[] encoding;
+ private int macKeySize;
+ private int cipherKeySize;
+
+
+ /**
+ * Set the IES engine parameters.
+ *
+ * @param derivation the optional derivation vector for the KDF.
+ * @param encoding the optional encoding vector for the KDF.
+ * @param macKeySize the key size (in bits) for the MAC.
+ */
+ public IESParameterSpec(
+ byte[] derivation,
+ byte[] encoding,
+ int macKeySize)
+ {
+ this(derivation, encoding, macKeySize, -1);
+ }
+
+
+ /**
+ * Set the IES engine parameters.
+ *
+ * @param derivation the optional derivation vector for the KDF.
+ * @param encoding the optional encoding vector for the KDF.
+ * @param macKeySize the key size (in bits) for the MAC.
+ * @param cipherKeySize the key size (in bits) for the block cipher.
+ */
+ public IESParameterSpec(
+ byte[] derivation,
+ byte[] encoding,
+ int macKeySize,
+ int cipherKeySize)
+ {
+ if (derivation != null)
+ {
+ this.derivation = new byte[derivation.length];
+ System.arraycopy(derivation, 0, this.derivation, 0, derivation.length);
+ }
+ else
+ {
+ this.derivation = null;
+ }
+
+ if (encoding != null)
+ {
+ this.encoding = new byte[encoding.length];
+ System.arraycopy(encoding, 0, this.encoding, 0, encoding.length);
+ }
+ else
+ {
+ this.encoding = null;
+ }
+
+ this.macKeySize = macKeySize;
+ this.cipherKeySize = cipherKeySize;
+ }
+
+
+ /**
+ * return the derivation vector.
+ */
+ public byte[] getDerivationV()
+ {
+ return derivation;
+ }
+
+ /**
+ * return the encoding vector.
+ */
+ public byte[] getEncodingV()
+ {
+ return encoding;
+ }
+
+ /**
+ * return the key size in bits for the MAC used with the message
+ */
+ public int getMacKeySize()
+ {
+ return macKeySize;
+ }
+
+ /**
+ * return the key size in bits for the block cipher used with the message
+ */
+ public int getCipherKeySize()
+ {
+ return cipherKeySize;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/MQVPrivateKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/MQVPrivateKeySpec.java
new file mode 100644
index 000000000..841726007
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/MQVPrivateKeySpec.java
@@ -0,0 +1,93 @@
+package org.spongycastle.jce.spec;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.jce.interfaces.MQVPrivateKey;
+
+/**
+ * Static/ephemeral private key (pair) for use with ECMQV key agreement
+ * (Optionally provides the ephemeral public key)
+ */
+public class MQVPrivateKeySpec
+ implements KeySpec, MQVPrivateKey
+{
+ private PrivateKey staticPrivateKey;
+ private PrivateKey ephemeralPrivateKey;
+ private PublicKey ephemeralPublicKey;
+
+ /**
+ * @param staticPrivateKey the static private key.
+ * @param ephemeralPrivateKey the ephemeral private key.
+ */
+ public MQVPrivateKeySpec(
+ PrivateKey staticPrivateKey,
+ PrivateKey ephemeralPrivateKey)
+ {
+ this(staticPrivateKey, ephemeralPrivateKey, null);
+ }
+
+ /**
+ * @param staticPrivateKey the static private key.
+ * @param ephemeralPrivateKey the ephemeral private key.
+ * @param ephemeralPublicKey the ephemeral public key (may be null).
+ */
+ public MQVPrivateKeySpec(
+ PrivateKey staticPrivateKey,
+ PrivateKey ephemeralPrivateKey,
+ PublicKey ephemeralPublicKey)
+ {
+ this.staticPrivateKey = staticPrivateKey;
+ this.ephemeralPrivateKey = ephemeralPrivateKey;
+ this.ephemeralPublicKey = ephemeralPublicKey;
+ }
+
+ /**
+ * return the static private key
+ */
+ public PrivateKey getStaticPrivateKey()
+ {
+ return staticPrivateKey;
+ }
+
+ /**
+ * return the ephemeral private key
+ */
+ public PrivateKey getEphemeralPrivateKey()
+ {
+ return ephemeralPrivateKey;
+ }
+
+ /**
+ * return the ephemeral public key (may be null)
+ */
+ public PublicKey getEphemeralPublicKey()
+ {
+ return ephemeralPublicKey;
+ }
+
+ /**
+ * return "ECMQV"
+ */
+ public String getAlgorithm()
+ {
+ return "ECMQV";
+ }
+
+ /**
+ * return null
+ */
+ public String getFormat()
+ {
+ return null;
+ }
+
+ /**
+ * returns null
+ */
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/MQVPublicKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/MQVPublicKeySpec.java
new file mode 100644
index 000000000..f32c46fd8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/MQVPublicKeySpec.java
@@ -0,0 +1,68 @@
+package org.spongycastle.jce.spec;
+
+import java.security.PublicKey;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.jce.interfaces.MQVPublicKey;
+
+/**
+ * Static/ephemeral public key pair for use with ECMQV key agreement
+ */
+public class MQVPublicKeySpec
+ implements KeySpec, MQVPublicKey
+{
+ private PublicKey staticKey;
+ private PublicKey ephemeralKey;
+
+ /**
+ * @param staticKey the static public key.
+ * @param ephemeralKey the ephemeral public key.
+ */
+ public MQVPublicKeySpec(
+ PublicKey staticKey,
+ PublicKey ephemeralKey)
+ {
+ this.staticKey = staticKey;
+ this.ephemeralKey = ephemeralKey;
+ }
+
+ /**
+ * return the static public key
+ */
+ public PublicKey getStaticKey()
+ {
+ return staticKey;
+ }
+
+ /**
+ * return the ephemeral public key
+ */
+ public PublicKey getEphemeralKey()
+ {
+ return ephemeralKey;
+ }
+
+ /**
+ * return "ECMQV"
+ */
+ public String getAlgorithm()
+ {
+ return "ECMQV";
+ }
+
+ /**
+ * return null
+ */
+ public String getFormat()
+ {
+ return null;
+ }
+
+ /**
+ * returns null
+ */
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/RepeatedSecretKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/RepeatedSecretKeySpec.java
new file mode 100644
index 000000000..d3012ecd0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/spec/RepeatedSecretKeySpec.java
@@ -0,0 +1,17 @@
+package org.spongycastle.jce.spec;
+
+/**
+ * A simple object to indicate that a symmetric cipher should reuse the
+ * last key provided.
+ * @deprecated use super class org.spongycastle.jcajce.spec.RepeatedSecretKeySpec
+ */
+public class RepeatedSecretKeySpec
+ extends org.spongycastle.jcajce.spec.RepeatedSecretKeySpec
+{
+ private String algorithm;
+
+ public RepeatedSecretKeySpec(String algorithm)
+ {
+ super(algorithm);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/BasicOCSPResp.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/BasicOCSPResp.java
new file mode 100644
index 000000000..f8d00f3bb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/BasicOCSPResp.java
@@ -0,0 +1,366 @@
+package org.spongycastle.ocsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.X509Certificate;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.ocsp.BasicOCSPResponse;
+import org.spongycastle.asn1.ocsp.ResponseData;
+import org.spongycastle.asn1.ocsp.SingleResponse;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+
+/**
+ * <pre>
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ * </pre>
+ *
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+public class BasicOCSPResp
+ implements java.security.cert.X509Extension
+{
+ BasicOCSPResponse resp;
+ ResponseData data;
+ X509Certificate[] chain = null;
+
+ public BasicOCSPResp(
+ BasicOCSPResponse resp)
+ {
+ this.resp = resp;
+ this.data = resp.getTbsResponseData();
+ }
+
+ /**
+ * Return the DER encoding of the tbsResponseData field.
+ * @return DER encoding of tbsResponseData
+ * @throws OCSPException in the event of an encoding error.
+ */
+ public byte[] getTBSResponseData()
+ throws OCSPException
+ {
+ try
+ {
+ return resp.getTbsResponseData().getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new OCSPException("problem encoding tbsResponseData", e);
+ }
+ }
+
+ public int getVersion()
+ {
+ return data.getVersion().getValue().intValue() + 1;
+ }
+
+ public RespID getResponderId()
+ {
+ return new RespID(data.getResponderID());
+ }
+
+ public Date getProducedAt()
+ {
+ try
+ {
+ return data.getProducedAt().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IllegalStateException("ParseException:" + e.getMessage());
+ }
+ }
+
+ public SingleResp[] getResponses()
+ {
+ ASN1Sequence s = data.getResponses();
+ SingleResp[] rs = new SingleResp[s.size()];
+
+ for (int i = 0; i != rs.length; i++)
+ {
+ rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i)));
+ }
+
+ return rs;
+ }
+
+ public X509Extensions getResponseExtensions()
+ {
+ return X509Extensions.getInstance(data.getResponseExtensions());
+ }
+
+ /**
+ * RFC 2650 doesn't specify any critical extensions so we return true
+ * if any are encountered.
+ *
+ * @return true if any critical extensions are present.
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+ if (extns != null && !extns.isEmpty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = this.getResponseExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+ }
+
+ return set;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ X509Extensions exts = this.getResponseExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String getSignatureAlgName()
+ {
+ return OCSPUtil.getAlgorithmName(resp.getSignatureAlgorithm().getObjectId());
+ }
+
+ public String getSignatureAlgOID()
+ {
+ return resp.getSignatureAlgorithm().getObjectId().getId();
+ }
+
+ /**
+ * @deprecated RespData class is no longer required as all functionality is
+ * available on this class.
+ * @return the RespData object
+ */
+ public RespData getResponseData()
+ {
+ return new RespData(resp.getTbsResponseData());
+ }
+
+ public byte[] getSignature()
+ {
+ return resp.getSignature().getBytes();
+ }
+
+ private List getCertList(
+ String provider)
+ throws OCSPException, NoSuchProviderException
+ {
+ List certs = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+ CertificateFactory cf;
+
+ try
+ {
+ cf = OCSPUtil.createX509CertificateFactory(provider);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OCSPException("can't get certificate factory.", ex);
+ }
+
+ //
+ // load the certificates and revocation lists if we have any
+ //
+ ASN1Sequence s = resp.getCerts();
+
+ if (s != null)
+ {
+ Enumeration e = s.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ certs.add(cf.generateCertificate(
+ new ByteArrayInputStream(bOut.toByteArray())));
+ }
+ catch (IOException ex)
+ {
+ throw new OCSPException(
+ "can't re-encode certificate!", ex);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OCSPException(
+ "can't re-encode certificate!", ex);
+ }
+
+ bOut.reset();
+ }
+ }
+
+ return certs;
+ }
+
+ public X509Certificate[] getCerts(
+ String provider)
+ throws OCSPException, NoSuchProviderException
+ {
+ List certs = getCertList(provider);
+
+ return (X509Certificate[])certs.toArray(new X509Certificate[certs.size()]);
+ }
+
+ /**
+ * Return the certificates, if any associated with the response.
+ * @param type type of CertStore to create
+ * @param provider provider to use
+ * @return a CertStore, possibly empty
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ * @throws OCSPException
+ */
+ public CertStore getCertificates(
+ String type,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException, OCSPException
+ {
+ try
+ {
+ CertStoreParameters params = new CollectionCertStoreParameters(this.getCertList(provider));
+ return OCSPUtil.createCertStoreInstance(type, params, provider);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new OCSPException("can't setup the CertStore", e);
+ }
+ }
+
+ /**
+ * verify the signature against the tbsResponseData object we contain.
+ */
+ public boolean verify(
+ PublicKey key,
+ String sigProvider)
+ throws OCSPException, NoSuchProviderException
+ {
+ try
+ {
+ Signature signature = OCSPUtil.createSignatureInstance(this.getSignatureAlgName(), sigProvider);
+
+ signature.initVerify(key);
+
+ signature.update(resp.getTbsResponseData().getEncoded(ASN1Encoding.DER));
+
+ return signature.verify(this.getSignature());
+ }
+ catch (NoSuchProviderException e)
+ {
+ // TODO Why this special case?
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing sig: " + e, e);
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return resp.getEncoded();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof BasicOCSPResp))
+ {
+ return false;
+ }
+
+ BasicOCSPResp r = (BasicOCSPResp)o;
+
+ return resp.equals(r.resp);
+ }
+
+ public int hashCode()
+ {
+ return resp.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/BasicOCSPRespGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/BasicOCSPRespGenerator.java
new file mode 100644
index 000000000..5c62b45f2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/BasicOCSPRespGenerator.java
@@ -0,0 +1,344 @@
+package org.spongycastle.ocsp;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.ocsp.BasicOCSPResponse;
+import org.spongycastle.asn1.ocsp.CertStatus;
+import org.spongycastle.asn1.ocsp.ResponseData;
+import org.spongycastle.asn1.ocsp.RevokedInfo;
+import org.spongycastle.asn1.ocsp.SingleResponse;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.X509CertificateStructure;
+import org.spongycastle.asn1.x509.X509Extensions;
+
+/**
+ * Generator for basic OCSP response objects.
+ *
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+public class BasicOCSPRespGenerator
+{
+ private List list = new ArrayList();
+ private X509Extensions responseExtensions = null;
+ private RespID responderID;
+
+ private class ResponseObject
+ {
+ CertificateID certId;
+ CertStatus certStatus;
+ DERGeneralizedTime thisUpdate;
+ DERGeneralizedTime nextUpdate;
+ X509Extensions extensions;
+
+ public ResponseObject(
+ CertificateID certId,
+ CertificateStatus certStatus,
+ Date thisUpdate,
+ Date nextUpdate,
+ X509Extensions extensions)
+ {
+ this.certId = certId;
+
+ if (certStatus == null)
+ {
+ this.certStatus = new CertStatus();
+ }
+ else if (certStatus instanceof UnknownStatus)
+ {
+ this.certStatus = new CertStatus(2, DERNull.INSTANCE);
+ }
+ else
+ {
+ RevokedStatus rs = (RevokedStatus)certStatus;
+
+ if (rs.hasRevocationReason())
+ {
+ this.certStatus = new CertStatus(
+ new RevokedInfo(new ASN1GeneralizedTime(rs.getRevocationTime()), CRLReason.lookup(rs.getRevocationReason())));
+ }
+ else
+ {
+ this.certStatus = new CertStatus(
+ new RevokedInfo(new ASN1GeneralizedTime(rs.getRevocationTime()), null));
+ }
+ }
+
+ this.thisUpdate = new DERGeneralizedTime(thisUpdate);
+
+ if (nextUpdate != null)
+ {
+ this.nextUpdate = new DERGeneralizedTime(nextUpdate);
+ }
+ else
+ {
+ this.nextUpdate = null;
+ }
+
+ this.extensions = extensions;
+ }
+
+ public SingleResponse toResponse()
+ throws Exception
+ {
+ return new SingleResponse(certId.toASN1Object(), certStatus, thisUpdate, nextUpdate, extensions);
+ }
+ }
+
+ /**
+ * basic constructor
+ */
+ public BasicOCSPRespGenerator(
+ RespID responderID)
+ {
+ this.responderID = responderID;
+ }
+
+ /**
+ * construct with the responderID to be the SHA-1 keyHash of the passed in public key.
+ */
+ public BasicOCSPRespGenerator(
+ PublicKey key)
+ throws OCSPException
+ {
+ this.responderID = new RespID(key);
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param certStatus status of the certificate - null if okay
+ */
+ public void addResponse(
+ CertificateID certID,
+ CertificateStatus certStatus)
+ {
+ list.add(new ResponseObject(certID, certStatus, new Date(), null, null));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void addResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ X509Extensions singleExtensions)
+ {
+ list.add(new ResponseObject(certID, certStatus, new Date(), null, singleExtensions));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param nextUpdate date when next update should be requested
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void addResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ Date nextUpdate,
+ X509Extensions singleExtensions)
+ {
+ list.add(new ResponseObject(certID, certStatus, new Date(), nextUpdate, singleExtensions));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param thisUpdate date this response was valid on
+ * @param nextUpdate date when next update should be requested
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void addResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ Date thisUpdate,
+ Date nextUpdate,
+ X509Extensions singleExtensions)
+ {
+ list.add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions));
+ }
+
+ /**
+ * Set the extensions for the response.
+ *
+ * @param responseExtensions the extension object to carry.
+ */
+ public void setResponseExtensions(
+ X509Extensions responseExtensions)
+ {
+ this.responseExtensions = responseExtensions;
+ }
+
+ private BasicOCSPResp generateResponse(
+ String signatureName,
+ PrivateKey key,
+ X509Certificate[] chain,
+ Date producedAt,
+ String provider,
+ SecureRandom random)
+ throws OCSPException, NoSuchProviderException
+ {
+ Iterator it = list.iterator();
+ DERObjectIdentifier signingAlgorithm;
+
+ try
+ {
+ signingAlgorithm = OCSPUtil.getAlgorithmOID(signatureName);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unknown signing algorithm specified");
+ }
+
+ ASN1EncodableVector responses = new ASN1EncodableVector();
+
+ while (it.hasNext())
+ {
+ try
+ {
+ responses.add(((ResponseObject)it.next()).toResponse());
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception creating Request", e);
+ }
+ }
+
+ ResponseData tbsResp = new ResponseData(responderID.toASN1Object(), new DERGeneralizedTime(producedAt), new DERSequence(responses), responseExtensions);
+
+ Signature sig = null;
+
+ try
+ {
+ sig = OCSPUtil.createSignatureInstance(signatureName, provider);
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ // TODO Why this special case?
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OCSPException("exception creating signature: " + e, e);
+ }
+
+ DERBitString bitSig = null;
+
+ try
+ {
+ sig.update(tbsResp.getEncoded(ASN1Encoding.DER));
+
+ bitSig = new DERBitString(sig.sign());
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing TBSRequest: " + e, e);
+ }
+
+ AlgorithmIdentifier sigAlgId = OCSPUtil.getSigAlgID(signingAlgorithm);
+
+ DERSequence chainSeq = null;
+ if (chain != null && chain.length > 0)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ try
+ {
+ for (int i = 0; i != chain.length; i++)
+ {
+ v.add(new X509CertificateStructure(
+ (ASN1Sequence)ASN1Primitive.fromByteArray(chain[i].getEncoded())));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new OCSPException("error processing certs", e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OCSPException("error encoding certs", e);
+ }
+
+ chainSeq = new DERSequence(v);
+ }
+
+ return new BasicOCSPResp(new BasicOCSPResponse(tbsResp, sigAlgId, bitSig, chainSeq));
+ }
+
+ public BasicOCSPResp generate(
+ String signingAlgorithm,
+ PrivateKey key,
+ X509Certificate[] chain,
+ Date thisUpdate,
+ String provider)
+ throws OCSPException, NoSuchProviderException, IllegalArgumentException
+ {
+ return generate(signingAlgorithm, key, chain, thisUpdate, provider, null);
+ }
+
+ public BasicOCSPResp generate(
+ String signingAlgorithm,
+ PrivateKey key,
+ X509Certificate[] chain,
+ Date producedAt,
+ String provider,
+ SecureRandom random)
+ throws OCSPException, NoSuchProviderException, IllegalArgumentException
+ {
+ if (signingAlgorithm == null)
+ {
+ throw new IllegalArgumentException("no signing algorithm specified");
+ }
+
+ return generateResponse(signingAlgorithm, key, chain, producedAt, provider, random);
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return OCSPUtil.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/CertificateID.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/CertificateID.java
new file mode 100644
index 000000000..cb86c29d5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/CertificateID.java
@@ -0,0 +1,170 @@
+package org.spongycastle.ocsp;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.CertID;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+
+public class CertificateID
+{
+ public static final String HASH_SHA1 = "1.3.14.3.2.26";
+
+ private final CertID id;
+
+ public CertificateID(
+ CertID id)
+ {
+ if (id == null)
+ {
+ throw new IllegalArgumentException("'id' cannot be null");
+ }
+ this.id = id;
+ }
+
+ /**
+ * create from an issuer certificate and the serial number of the
+ * certificate it signed.
+ *
+ * @param hashAlgorithm hash algorithm to use
+ * @param issuerCert issuing certificate
+ * @param number serial number
+ * @param provider provider to use for hashAlgorithm, null if the default one should be used.
+ *
+ * @exception OCSPException if any problems occur creating the id fields.
+ */
+ public CertificateID(
+ String hashAlgorithm,
+ X509Certificate issuerCert,
+ BigInteger number,
+ String provider)
+ throws OCSPException
+ {
+ AlgorithmIdentifier hashAlg = new AlgorithmIdentifier(
+ new DERObjectIdentifier(hashAlgorithm), DERNull.INSTANCE);
+
+ this.id = createCertID(hashAlg, issuerCert, new ASN1Integer(number), provider);
+ }
+
+ /**
+ * create using the BC provider
+ */
+ public CertificateID(
+ String hashAlgorithm,
+ X509Certificate issuerCert,
+ BigInteger number)
+ throws OCSPException
+ {
+ this(hashAlgorithm, issuerCert, number, "SC");
+ }
+
+ public String getHashAlgOID()
+ {
+ return id.getHashAlgorithm().getObjectId().getId();
+ }
+
+ public byte[] getIssuerNameHash()
+ {
+ return id.getIssuerNameHash().getOctets();
+ }
+
+ public byte[] getIssuerKeyHash()
+ {
+ return id.getIssuerKeyHash().getOctets();
+ }
+
+ /**
+ * return the serial number for the certificate associated
+ * with this request.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return id.getSerialNumber().getValue();
+ }
+
+ public boolean matchesIssuer(X509Certificate issuerCert, String provider)
+ throws OCSPException
+ {
+ return createCertID(id.getHashAlgorithm(), issuerCert, id.getSerialNumber(), provider)
+ .equals(id);
+ }
+
+ public CertID toASN1Object()
+ {
+ return id;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof CertificateID))
+ {
+ return false;
+ }
+
+ CertificateID obj = (CertificateID)o;
+
+ return id.toASN1Primitive().equals(obj.id.toASN1Primitive());
+ }
+
+ public int hashCode()
+ {
+ return id.toASN1Primitive().hashCode();
+ }
+
+ /**
+ * Create a new CertificateID for a new serial number derived from a previous one
+ * calculated for the same CA certificate.
+ *
+ * @param original the previously calculated CertificateID for the CA.
+ * @param newSerialNumber the serial number for the new certificate of interest.
+ *
+ * @return a new CertificateID for newSerialNumber
+ */
+ public static CertificateID deriveCertificateID(CertificateID original, BigInteger newSerialNumber)
+ {
+ return new CertificateID(new CertID(original.id.getHashAlgorithm(), original.id.getIssuerNameHash(), original.id.getIssuerKeyHash(), new ASN1Integer(newSerialNumber)));
+ }
+
+ private static CertID createCertID(AlgorithmIdentifier hashAlg, X509Certificate issuerCert,
+ ASN1Integer serialNumber, String provider)
+ throws OCSPException
+ {
+ try
+ {
+ MessageDigest digest = OCSPUtil.createDigestInstance(hashAlg.getAlgorithm() .getId(),
+ provider);
+
+ X509Principal issuerName = PrincipalUtil.getSubjectX509Principal(issuerCert);
+
+ digest.update(issuerName.getEncoded());
+
+ ASN1OctetString issuerNameHash = new DEROctetString(digest.digest());
+ PublicKey issuerKey = issuerCert.getPublicKey();
+
+ ASN1InputStream aIn = new ASN1InputStream(issuerKey.getEncoded());
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ digest.update(info.getPublicKeyData().getBytes());
+
+ ASN1OctetString issuerKeyHash = new DEROctetString(digest.digest());
+
+ return new CertID(hashAlg, issuerNameHash, issuerKeyHash, serialNumber);
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("problem creating ID: " + e, e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/CertificateStatus.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/CertificateStatus.java
new file mode 100644
index 000000000..d84b179b5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/CertificateStatus.java
@@ -0,0 +1,6 @@
+package org.spongycastle.ocsp;
+
+public interface CertificateStatus
+{
+ public static final CertificateStatus GOOD = null;
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPException.java
new file mode 100644
index 000000000..61516757f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPException.java
@@ -0,0 +1,32 @@
+package org.spongycastle.ocsp;
+
+public class OCSPException
+ extends Exception
+{
+ Exception e;
+
+ public OCSPException(
+ String name)
+ {
+ super(name);
+ }
+
+ public OCSPException(
+ String name,
+ Exception e)
+ {
+ super(name);
+
+ this.e = e;
+ }
+
+ public Exception getUnderlyingException()
+ {
+ return e;
+ }
+
+ public Throwable getCause()
+ {
+ return e;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPReq.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPReq.java
new file mode 100644
index 000000000..6e00fd8db
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPReq.java
@@ -0,0 +1,417 @@
+package org.spongycastle.ocsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ocsp.OCSPRequest;
+import org.spongycastle.asn1.ocsp.Request;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+
+/**
+ * <pre>
+ * OCSPRequest ::= SEQUENCE {
+ * tbsRequest TBSRequest,
+ * optionalSignature [0] EXPLICIT Signature OPTIONAL }
+ *
+ * TBSRequest ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ * requestList SEQUENCE OF Request,
+ * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+ *
+ * Signature ::= SEQUENCE {
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+ *
+ * Version ::= INTEGER { v1(0) }
+ *
+ * Request ::= SEQUENCE {
+ * reqCert CertID,
+ * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+ *
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ * serialNumber CertificateSerialNumber }
+ * </pre>
+ *
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+public class OCSPReq
+ implements java.security.cert.X509Extension
+{
+ private OCSPRequest req;
+
+ public OCSPReq(
+ OCSPRequest req)
+ {
+ this.req = req;
+ }
+
+ public OCSPReq(
+ byte[] req)
+ throws IOException
+ {
+ this(new ASN1InputStream(req));
+ }
+
+ public OCSPReq(
+ InputStream in)
+ throws IOException
+ {
+ this(new ASN1InputStream(in));
+ }
+
+ private OCSPReq(
+ ASN1InputStream aIn)
+ throws IOException
+ {
+ try
+ {
+ this.req = OCSPRequest.getInstance(aIn.readObject());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("malformed request: " + e.getMessage());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("malformed request: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Return the DER encoding of the tbsRequest field.
+ * @return DER encoding of tbsRequest
+ * @throws OCSPException in the event of an encoding error.
+ */
+ public byte[] getTBSRequest()
+ throws OCSPException
+ {
+ try
+ {
+ return req.getTbsRequest().getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new OCSPException("problem encoding tbsRequest", e);
+ }
+ }
+
+ public int getVersion()
+ {
+ return req.getTbsRequest().getVersion().getValue().intValue() + 1;
+ }
+
+ public GeneralName getRequestorName()
+ {
+ return GeneralName.getInstance(req.getTbsRequest().getRequestorName());
+ }
+
+ public Req[] getRequestList()
+ {
+ ASN1Sequence seq = req.getTbsRequest().getRequestList();
+ Req[] requests = new Req[seq.size()];
+
+ for (int i = 0; i != requests.length; i++)
+ {
+ requests[i] = new Req(Request.getInstance(seq.getObjectAt(i)));
+ }
+
+ return requests;
+ }
+
+ public X509Extensions getRequestExtensions()
+ {
+ return X509Extensions.getInstance(req.getTbsRequest().getRequestExtensions());
+ }
+
+ /**
+ * return the object identifier representing the signature algorithm
+ */
+ public String getSignatureAlgOID()
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ return req.getOptionalSignature().getSignatureAlgorithm().getObjectId().getId();
+ }
+
+ public byte[] getSignature()
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ return req.getOptionalSignature().getSignature().getBytes();
+ }
+
+ private List getCertList(
+ String provider)
+ throws OCSPException, NoSuchProviderException
+ {
+ List certs = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+ CertificateFactory cf;
+
+ try
+ {
+ cf = OCSPUtil.createX509CertificateFactory(provider);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OCSPException("can't get certificate factory.", ex);
+ }
+
+ //
+ // load the certificates if we have any
+ //
+ ASN1Sequence s = req.getOptionalSignature().getCerts();
+
+ if (s != null)
+ {
+ Enumeration e = s.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ certs.add(cf.generateCertificate(
+ new ByteArrayInputStream(bOut.toByteArray())));
+ }
+ catch (IOException ex)
+ {
+ throw new OCSPException(
+ "can't re-encode certificate!", ex);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OCSPException(
+ "can't re-encode certificate!", ex);
+ }
+
+ bOut.reset();
+ }
+ }
+
+ return certs;
+ }
+
+ public X509Certificate[] getCerts(
+ String provider)
+ throws OCSPException, NoSuchProviderException
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ List certs = this.getCertList(provider);
+
+ return (X509Certificate[])certs.toArray(new X509Certificate[certs.size()]);
+ }
+
+ /**
+ * If the request is signed return a possibly empty CertStore containing the certificates in the
+ * request. If the request is not signed the method returns null.
+ *
+ * @param type type of CertStore to return
+ * @param provider provider to use
+ * @return null if not signed, a CertStore otherwise
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ * @throws OCSPException
+ */
+ public CertStore getCertificates(
+ String type,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException, OCSPException
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ try
+ {
+ CertStoreParameters params = new CollectionCertStoreParameters(this.getCertList(provider));
+ return OCSPUtil.createCertStoreInstance(type, params, provider);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new OCSPException("can't setup the CertStore", e);
+ }
+ }
+
+ /**
+ * Return whether or not this request is signed.
+ *
+ * @return true if signed false otherwise.
+ */
+ public boolean isSigned()
+ {
+ return req.getOptionalSignature() != null;
+ }
+
+ /**
+ * verify the signature against the TBSRequest object we contain.
+ */
+ public boolean verify(
+ PublicKey key,
+ String sigProvider)
+ throws OCSPException, NoSuchProviderException
+ {
+ if (!this.isSigned())
+ {
+ throw new OCSPException("attempt to verify signature on unsigned object");
+ }
+
+ try
+ {
+ Signature signature = OCSPUtil.createSignatureInstance(this.getSignatureAlgOID(), sigProvider);
+
+ signature.initVerify(key);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(req.getTbsRequest());
+
+ signature.update(bOut.toByteArray());
+
+ return signature.verify(this.getSignature());
+ }
+ catch (NoSuchProviderException e)
+ {
+ // TODO Why this special case?
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing sig: " + e, e);
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(req);
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * RFC 2650 doesn't specify any critical extensions so we return true
+ * if any are encountered.
+ *
+ * @return true if any critical extensions are present.
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+ if (extns != null && !extns.isEmpty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = this.getRequestExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+ }
+
+ return set;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ X509Extensions exts = this.getRequestExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPReqGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPReqGenerator.java
new file mode 100644
index 000000000..4e86d24b6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPReqGenerator.java
@@ -0,0 +1,294 @@
+package org.spongycastle.ocsp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.ocsp.OCSPRequest;
+import org.spongycastle.asn1.ocsp.Request;
+import org.spongycastle.asn1.ocsp.Signature;
+import org.spongycastle.asn1.ocsp.TBSRequest;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.X509CertificateStructure;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.X509Principal;
+
+/**
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+public class OCSPReqGenerator
+{
+ private List list = new ArrayList();
+ private GeneralName requestorName = null;
+ private X509Extensions requestExtensions = null;
+
+ private class RequestObject
+ {
+ CertificateID certId;
+ X509Extensions extensions;
+
+ public RequestObject(
+ CertificateID certId,
+ X509Extensions extensions)
+ {
+ this.certId = certId;
+ this.extensions = extensions;
+ }
+
+ public Request toRequest()
+ throws Exception
+ {
+ return new Request(certId.toASN1Object(), Extensions.getInstance(extensions));
+ }
+ }
+
+ /**
+ * Add a request for the given CertificateID.
+ *
+ * @param certId certificate ID of interest
+ */
+ public void addRequest(
+ CertificateID certId)
+ {
+ list.add(new RequestObject(certId, null));
+ }
+
+ /**
+ * Add a request with extensions
+ *
+ * @param certId certificate ID of interest
+ * @param singleRequestExtensions the extensions to attach to the request
+ */
+ public void addRequest(
+ CertificateID certId,
+ X509Extensions singleRequestExtensions)
+ {
+ list.add(new RequestObject(certId, singleRequestExtensions));
+ }
+
+ /**
+ * Set the requestor name to the passed in X500Principal
+ *
+ * @param requestorName a X500Principal representing the requestor name.
+ */
+ public void setRequestorName(
+ X500Principal requestorName)
+ {
+ try
+ {
+ this.requestorName = new GeneralName(GeneralName.directoryName, new X509Principal(requestorName.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("cannot encode principal: " + e);
+ }
+ }
+
+ public void setRequestorName(
+ GeneralName requestorName)
+ {
+ this.requestorName = requestorName;
+ }
+
+ public void setRequestExtensions(
+ X509Extensions requestExtensions)
+ {
+ this.requestExtensions = requestExtensions;
+ }
+
+ private OCSPReq generateRequest(
+ DERObjectIdentifier signingAlgorithm,
+ PrivateKey key,
+ X509Certificate[] chain,
+ String provider,
+ SecureRandom random)
+ throws OCSPException, NoSuchProviderException
+ {
+ Iterator it = list.iterator();
+
+ ASN1EncodableVector requests = new ASN1EncodableVector();
+
+ while (it.hasNext())
+ {
+ try
+ {
+ requests.add(((RequestObject)it.next()).toRequest());
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception creating Request", e);
+ }
+ }
+
+ TBSRequest tbsReq = new TBSRequest(requestorName, new DERSequence(requests), requestExtensions);
+
+ java.security.Signature sig = null;
+ Signature signature = null;
+
+ if (signingAlgorithm != null)
+ {
+ if (requestorName == null)
+ {
+ throw new OCSPException("requestorName must be specified if request is signed.");
+ }
+
+ try
+ {
+ sig = OCSPUtil.createSignatureInstance(signingAlgorithm.getId(), provider);
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ // TODO Why this special case?
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OCSPException("exception creating signature: " + e, e);
+ }
+
+ DERBitString bitSig = null;
+
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(tbsReq);
+
+ sig.update(bOut.toByteArray());
+
+ bitSig = new DERBitString(sig.sign());
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing TBSRequest: " + e, e);
+ }
+
+ AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(signingAlgorithm, DERNull.INSTANCE);
+
+ if (chain != null && chain.length > 0)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ try
+ {
+ for (int i = 0; i != chain.length; i++)
+ {
+ v.add(new X509CertificateStructure(
+ (ASN1Sequence)ASN1Primitive.fromByteArray(chain[i].getEncoded())));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new OCSPException("error processing certs", e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OCSPException("error encoding certs", e);
+ }
+
+ signature = new Signature(sigAlgId, bitSig, new DERSequence(v));
+ }
+ else
+ {
+ signature = new Signature(sigAlgId, bitSig);
+ }
+ }
+
+ return new OCSPReq(new OCSPRequest(tbsReq, signature));
+ }
+
+ /**
+ * Generate an unsigned request
+ *
+ * @return the OCSPReq
+ * @throws OCSPException
+ */
+ public OCSPReq generate()
+ throws OCSPException
+ {
+ try
+ {
+ return generateRequest(null, null, null, null, null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ //
+ // this shouldn't happen but...
+ //
+ throw new OCSPException("no provider! - " + e, e);
+ }
+ }
+
+ public OCSPReq generate(
+ String signingAlgorithm,
+ PrivateKey key,
+ X509Certificate[] chain,
+ String provider)
+ throws OCSPException, NoSuchProviderException, IllegalArgumentException
+ {
+ return generate(signingAlgorithm, key, chain, provider, null);
+ }
+
+ public OCSPReq generate(
+ String signingAlgorithm,
+ PrivateKey key,
+ X509Certificate[] chain,
+ String provider,
+ SecureRandom random)
+ throws OCSPException, NoSuchProviderException, IllegalArgumentException
+ {
+ if (signingAlgorithm == null)
+ {
+ throw new IllegalArgumentException("no signing algorithm specified");
+ }
+
+ try
+ {
+ DERObjectIdentifier oid = OCSPUtil.getAlgorithmOID(signingAlgorithm);
+
+ return generateRequest(oid, key, chain, provider, random);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IllegalArgumentException("unknown signing algorithm specified: " + signingAlgorithm);
+ }
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return OCSPUtil.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPResp.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPResp.java
new file mode 100644
index 000000000..fccd7d156
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPResp.java
@@ -0,0 +1,128 @@
+package org.spongycastle.ocsp;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ocsp.BasicOCSPResponse;
+import org.spongycastle.asn1.ocsp.OCSPObjectIdentifiers;
+import org.spongycastle.asn1.ocsp.OCSPResponse;
+import org.spongycastle.asn1.ocsp.ResponseBytes;
+
+/**
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+public class OCSPResp
+{
+ private OCSPResponse resp;
+
+ /**
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+ public OCSPResp(
+ OCSPResponse resp)
+ {
+ this.resp = resp;
+ }
+
+ /**
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+ public OCSPResp(
+ byte[] resp)
+ throws IOException
+ {
+ this(new ASN1InputStream(resp));
+ }
+
+ /**
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+ public OCSPResp(
+ InputStream in)
+ throws IOException
+ {
+ this(new ASN1InputStream(in));
+ }
+
+ private OCSPResp(
+ ASN1InputStream aIn)
+ throws IOException
+ {
+ try
+ {
+ this.resp = OCSPResponse.getInstance(aIn.readObject());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("malformed response: " + e.getMessage());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("malformed response: " + e.getMessage());
+ }
+ }
+
+ public int getStatus()
+ {
+ return this.resp.getResponseStatus().getValue().intValue();
+ }
+
+ public Object getResponseObject()
+ throws OCSPException
+ {
+ ResponseBytes rb = this.resp.getResponseBytes();
+
+ if (rb == null)
+ {
+ return null;
+ }
+
+ if (rb.getResponseType().equals(OCSPObjectIdentifiers.id_pkix_ocsp_basic))
+ {
+ try
+ {
+ ASN1Primitive obj = ASN1Primitive.fromByteArray(rb.getResponse().getOctets());
+ return new BasicOCSPResp(BasicOCSPResponse.getInstance(obj));
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("problem decoding object: " + e, e);
+ }
+ }
+
+ return rb.getResponse();
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return resp.getEncoded();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof OCSPResp))
+ {
+ return false;
+ }
+
+ OCSPResp r = (OCSPResp)o;
+
+ return resp.equals(r.resp);
+ }
+
+ public int hashCode()
+ {
+ return resp.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPRespGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPRespGenerator.java
new file mode 100644
index 000000000..791705d12
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPRespGenerator.java
@@ -0,0 +1,60 @@
+package org.spongycastle.ocsp;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.OCSPObjectIdentifiers;
+import org.spongycastle.asn1.ocsp.OCSPResponse;
+import org.spongycastle.asn1.ocsp.OCSPResponseStatus;
+import org.spongycastle.asn1.ocsp.ResponseBytes;
+
+/**
+ * base generator for an OCSP response - at the moment this only supports the
+ * generation of responses containing BasicOCSP responses.
+ *
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+public class OCSPRespGenerator
+{
+ public static final int SUCCESSFUL = 0; // Response has valid confirmations
+ public static final int MALFORMED_REQUEST = 1; // Illegal confirmation request
+ public static final int INTERNAL_ERROR = 2; // Internal error in issuer
+ public static final int TRY_LATER = 3; // Try again later
+ // (4) is not used
+ public static final int SIG_REQUIRED = 5; // Must sign the request
+ public static final int UNAUTHORIZED = 6; // Request unauthorized
+
+ public OCSPResp generate(
+ int status,
+ Object response)
+ throws OCSPException
+ {
+ if (response == null)
+ {
+ return new OCSPResp(new OCSPResponse(new OCSPResponseStatus(status),null));
+ }
+ if (response instanceof BasicOCSPResp)
+ {
+ BasicOCSPResp r = (BasicOCSPResp)response;
+ ASN1OctetString octs;
+
+ try
+ {
+ octs = new DEROctetString(r.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new OCSPException("can't encode object.", e);
+ }
+
+ ResponseBytes rb = new ResponseBytes(
+ OCSPObjectIdentifiers.id_pkix_ocsp_basic, octs);
+
+ return new OCSPResp(new OCSPResponse(
+ new OCSPResponseStatus(status), rb));
+ }
+
+ throw new OCSPException("unknown response object");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPRespStatus.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPRespStatus.java
new file mode 100644
index 000000000..dde33ce8a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPRespStatus.java
@@ -0,0 +1,14 @@
+package org.spongycastle.ocsp;
+
+public interface OCSPRespStatus
+{
+ /**
+ * note 4 is not used.
+ */
+ public static final int SUCCESSFUL = 0; // --Response has valid confirmations
+ public static final int MALFORMED_REQUEST = 1; // --Illegal confirmation request
+ public static final int INTERNAL_ERROR = 2; // --Internal error in issuer
+ public static final int TRY_LATER = 3; // --Try again later
+ public static final int SIGREQUIRED = 5; // --Must sign the request
+ public static final int UNAUTHORIZED = 6; // --Request unauthorized
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPUtil.java
new file mode 100644
index 000000000..1d4ba6cf3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/OCSPUtil.java
@@ -0,0 +1,198 @@
+package org.spongycastle.ocsp;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.util.Strings;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+class OCSPUtil
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable oids = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+
+ oids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2WITHRSA");
+ oids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, "RIPEMD160WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, "RIPEMD128WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, "RIPEMD256WITHRSA");
+ oids.put(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ }
+
+ static DERObjectIdentifier getAlgorithmOID(
+ String algorithmName)
+ {
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (algorithms.containsKey(algorithmName))
+ {
+ return (DERObjectIdentifier)algorithms.get(algorithmName);
+ }
+
+ return new DERObjectIdentifier(algorithmName);
+ }
+
+ static String getAlgorithmName(
+ DERObjectIdentifier oid)
+ {
+ if (oids.containsKey(oid))
+ {
+ return (String)oids.get(oid);
+ }
+
+ return oid.getId();
+ }
+
+ static AlgorithmIdentifier getSigAlgID(
+ DERObjectIdentifier sigOid)
+ {
+ if (noParams.contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+ else
+ {
+ return new AlgorithmIdentifier(sigOid, DERNull.INSTANCE);
+ }
+ }
+
+ static Iterator getAlgNames()
+ {
+ Enumeration e = algorithms.keys();
+ List l = new ArrayList();
+
+ while (e.hasMoreElements())
+ {
+ l.add(e.nextElement());
+ }
+
+ return l.iterator();
+ }
+
+ static CertStore createCertStoreInstance(String type, CertStoreParameters params, String provider)
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return CertStore.getInstance(type, params);
+ }
+
+ return CertStore.getInstance(type, params, provider);
+ }
+
+ static MessageDigest createDigestInstance(String digestName, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return MessageDigest.getInstance(digestName);
+ }
+
+ return MessageDigest.getInstance(digestName, provider);
+ }
+
+ static Signature createSignatureInstance(String sigName, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return Signature.getInstance(sigName);
+ }
+
+ return Signature.getInstance(sigName, provider);
+ }
+
+ static CertificateFactory createX509CertificateFactory(String provider)
+ throws CertificateException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return CertificateFactory.getInstance("X.509");
+ }
+
+ return CertificateFactory.getInstance("X.509", provider);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/Req.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/Req.java
new file mode 100644
index 000000000..7f67a5622
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/Req.java
@@ -0,0 +1,108 @@
+package org.spongycastle.ocsp;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.ocsp.Request;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+
+public class Req
+ implements java.security.cert.X509Extension
+{
+ private Request req;
+
+ public Req(
+ Request req)
+ {
+ this.req = req;
+ }
+
+ public CertificateID getCertID()
+ {
+ return new CertificateID(req.getReqCert());
+ }
+
+ public X509Extensions getSingleRequestExtensions()
+ {
+ return X509Extensions.getInstance(req.getSingleRequestExtensions());
+ }
+
+ /**
+ * RFC 2650 doesn't specify any critical extensions so we return true
+ * if any are encountered.
+ *
+ * @return true if any critical extensions are present.
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+ if (extns != null && !extns.isEmpty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = this.getSingleRequestExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+ }
+
+ return set;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ X509Extensions exts = this.getSingleRequestExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RespData.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RespData.java
new file mode 100644
index 000000000..10095546d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RespData.java
@@ -0,0 +1,142 @@
+package org.spongycastle.ocsp;
+
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.ocsp.ResponseData;
+import org.spongycastle.asn1.ocsp.SingleResponse;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+
+public class RespData
+ implements java.security.cert.X509Extension
+{
+ ResponseData data;
+
+ public RespData(
+ ResponseData data)
+ {
+ this.data = data;
+ }
+
+ public int getVersion()
+ {
+ return data.getVersion().getValue().intValue() + 1;
+ }
+
+ public RespID getResponderId()
+ {
+ return new RespID(data.getResponderID());
+ }
+
+ public Date getProducedAt()
+ {
+ try
+ {
+ return data.getProducedAt().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IllegalStateException("ParseException:" + e.getMessage());
+ }
+ }
+
+ public SingleResp[] getResponses()
+ {
+ ASN1Sequence s = data.getResponses();
+ SingleResp[] rs = new SingleResp[s.size()];
+
+ for (int i = 0; i != rs.length; i++)
+ {
+ rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i)));
+ }
+
+ return rs;
+ }
+
+ public X509Extensions getResponseExtensions()
+ {
+ return X509Extensions.getInstance(data.getResponseExtensions());
+ }
+
+ /**
+ * RFC 2650 doesn't specify any critical extensions so we return true
+ * if any are encountered.
+ *
+ * @return true if any critical extensions are present.
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+ if (extns != null && !extns.isEmpty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = this.getResponseExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+ }
+
+ return set;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ X509Extensions exts = this.getResponseExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RespID.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RespID.java
new file mode 100644
index 000000000..18c471886
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RespID.java
@@ -0,0 +1,80 @@
+package org.spongycastle.ocsp;
+
+import java.security.MessageDigest;
+import java.security.PublicKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.ResponderID;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * Carrier for a ResponderID.
+ */
+public class RespID
+{
+ ResponderID id;
+
+ public RespID(
+ ResponderID id)
+ {
+ this.id = id;
+ }
+
+ public RespID(
+ X500Principal name)
+ {
+ this.id = new ResponderID(X500Name.getInstance(name.getEncoded()));
+ }
+
+ public RespID(
+ PublicKey key)
+ throws OCSPException
+ {
+ try
+ {
+ // TODO Allow specification of a particular provider
+ MessageDigest digest = OCSPUtil.createDigestInstance("SHA1", null);
+
+ ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ digest.update(info.getPublicKeyData().getBytes());
+
+ ASN1OctetString keyHash = new DEROctetString(digest.digest());
+
+ this.id = new ResponderID(keyHash);
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("problem creating ID: " + e, e);
+ }
+ }
+
+ public ResponderID toASN1Object()
+ {
+ return id;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof RespID))
+ {
+ return false;
+ }
+
+ RespID obj = (RespID)o;
+
+ return id.equals(obj.id);
+ }
+
+ public int hashCode()
+ {
+ return id.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RevokedStatus.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RevokedStatus.java
new file mode 100644
index 000000000..4643d53b1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/RevokedStatus.java
@@ -0,0 +1,63 @@
+package org.spongycastle.ocsp;
+
+import java.text.ParseException;
+import java.util.Date;
+
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ocsp.RevokedInfo;
+import org.spongycastle.asn1.x509.CRLReason;
+
+/**
+ * wrapper for the RevokedInfo object
+ */
+public class RevokedStatus
+ implements CertificateStatus
+{
+ RevokedInfo info;
+
+ public RevokedStatus(
+ RevokedInfo info)
+ {
+ this.info = info;
+ }
+
+ public RevokedStatus(
+ Date revocationDate,
+ int reason)
+ {
+ this.info = new RevokedInfo(new ASN1GeneralizedTime(revocationDate), CRLReason.lookup(reason));
+ }
+
+ public Date getRevocationTime()
+ {
+ try
+ {
+ return info.getRevocationTime().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IllegalStateException("ParseException:" + e.getMessage());
+ }
+ }
+
+ public boolean hasRevocationReason()
+ {
+ return (info.getRevocationReason() != null);
+ }
+
+ /**
+ * return the revocation reason. Note: this field is optional, test for it
+ * with hasRevocationReason() first.
+ * @return the revocation reason value.
+ * @exception IllegalStateException if a reason is asked for and none is avaliable
+ */
+ public int getRevocationReason()
+ {
+ if (info.getRevocationReason() == null)
+ {
+ throw new IllegalStateException("attempt to get a reason where none is available");
+ }
+
+ return info.getRevocationReason().getValue().intValue();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/SingleResp.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/SingleResp.java
new file mode 100644
index 000000000..ead05d93a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/SingleResp.java
@@ -0,0 +1,164 @@
+package org.spongycastle.ocsp;
+
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.ocsp.CertStatus;
+import org.spongycastle.asn1.ocsp.RevokedInfo;
+import org.spongycastle.asn1.ocsp.SingleResponse;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+
+public class SingleResp
+ implements java.security.cert.X509Extension
+{
+ SingleResponse resp;
+
+ public SingleResp(
+ SingleResponse resp)
+ {
+ this.resp = resp;
+ }
+
+ public CertificateID getCertID()
+ {
+ return new CertificateID(resp.getCertID());
+ }
+
+ /**
+ * Return the status object for the response - null indicates good.
+ *
+ * @return the status object for the response, null if it is good.
+ */
+ public Object getCertStatus()
+ {
+ CertStatus s = resp.getCertStatus();
+
+ if (s.getTagNo() == 0)
+ {
+ return null; // good
+ }
+ else if (s.getTagNo() == 1)
+ {
+ return new RevokedStatus(RevokedInfo.getInstance(s.getStatus()));
+ }
+
+ return new UnknownStatus();
+ }
+
+ public Date getThisUpdate()
+ {
+ try
+ {
+ return resp.getThisUpdate().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IllegalStateException("ParseException: " + e.getMessage());
+ }
+ }
+
+ /**
+ * return the NextUpdate value - note: this is an optional field so may
+ * be returned as null.
+ *
+ * @return nextUpdate, or null if not present.
+ */
+ public Date getNextUpdate()
+ {
+ if (resp.getNextUpdate() == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ return resp.getNextUpdate().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IllegalStateException("ParseException: " + e.getMessage());
+ }
+ }
+
+ public X509Extensions getSingleExtensions()
+ {
+ return X509Extensions.getInstance(resp.getSingleExtensions());
+ }
+
+ /**
+ * RFC 2650 doesn't specify any critical extensions so we return true
+ * if any are encountered.
+ *
+ * @return true if any critical extensions are present.
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ return extns != null && !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = this.getSingleExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+ }
+
+ return set;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ X509Extensions exts = this.getSingleExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/UnknownStatus.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/UnknownStatus.java
new file mode 100644
index 000000000..d8b503970
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/ocsp/UnknownStatus.java
@@ -0,0 +1,12 @@
+package org.spongycastle.ocsp;
+
+/**
+ * wrapper for the UnknownInfo object
+ */
+public class UnknownStatus
+ implements CertificateStatus
+{
+ public UnknownStatus()
+ {
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
new file mode 100644
index 000000000..b237aee47
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
@@ -0,0 +1,157 @@
+package org.spongycastle.pqc.jcajce.provider;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivateKey;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class BouncyCastlePQCProvider
+ extends Provider
+ implements ConfigurableProvider
+{
+ private static String info = "BouncyCastle Post-Quantum Security Provider v1.50";
+
+ public static String PROVIDER_NAME = "BCPQC";
+
+ public static final ProviderConfiguration CONFIGURATION = null;
+
+
+ private static final Map keyInfoConverters = new HashMap();
+
+ /*
+ * Configurable symmetric ciphers
+ */
+ private static final String ALGORITHM_PACKAGE = "org.spongycastle.pqc.jcajce.provider.";
+ private static final String[] ALGORITHMS =
+ {
+ "Rainbow", "McEliece"
+ };
+
+ /**
+ * Construct a new provider. This should only be required when
+ * using runtime registration of the provider using the
+ * <code>Security.addProvider()</code> mechanism.
+ */
+ public BouncyCastlePQCProvider()
+ {
+ super(PROVIDER_NAME, 1.50, info);
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ setup();
+ return null;
+ }
+ });
+ }
+
+ private void setup()
+ {
+ loadAlgorithms(ALGORITHM_PACKAGE, ALGORITHMS);
+ }
+
+ private void loadAlgorithms(String packageName, String[] names)
+ {
+ for (int i = 0; i != names.length; i++)
+ {
+ Class clazz = null;
+ try
+ {
+ ClassLoader loader = this.getClass().getClassLoader();
+
+ if (loader != null)
+ {
+ clazz = loader.loadClass(packageName + names[i] + "$Mappings");
+ }
+ else
+ {
+ clazz = Class.forName(packageName + names[i] + "$Mappings");
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ // ignore
+ }
+
+ if (clazz != null)
+ {
+ try
+ {
+ ((AlgorithmProvider)clazz.newInstance()).configure(this);
+ }
+ catch (Exception e)
+ { // this should never ever happen!!
+ throw new InternalError("cannot create instance of "
+ + packageName + names[i] + "$Mappings : " + e);
+ }
+ }
+ }
+ }
+
+ public void setParameter(String parameterName, Object parameter)
+ {
+ synchronized (CONFIGURATION)
+ {
+ //((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
+ }
+ }
+
+ public boolean hasAlgorithm(String type, String name)
+ {
+ return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
+ }
+
+ public void addAlgorithm(String key, String value)
+ {
+ if (containsKey(key))
+ {
+ throw new IllegalStateException("duplicate provider key (" + key + ") found");
+ }
+
+ put(key, value);
+ }
+
+ public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
+ {
+ keyInfoConverters.put(oid, keyInfoConverter);
+ }
+
+ public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePublic(publicKeyInfo);
+ }
+
+ public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePrivate(privateKeyInfo);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/McEliece.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/McEliece.java
new file mode 100644
index 000000000..06f16f850
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/McEliece.java
@@ -0,0 +1,62 @@
+package org.spongycastle.pqc.jcajce.provider;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+
+public class McEliece
+{
+ private static final String PREFIX = "org.spongycastle.pqc.jcajce.provider" + ".mceliece.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ // McElieceKobaraImai
+ provider.addAlgorithm("KeyPairGenerator.McElieceKobaraImai", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
+ // McEliecePointcheval
+ provider.addAlgorithm("KeyPairGenerator.McEliecePointcheval", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
+ // McElieceFujisaki
+ provider.addAlgorithm("KeyPairGenerator.McElieceFujisaki", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
+ // McEliecePKCS
+ provider.addAlgorithm("KeyPairGenerator.McEliecePKCS", PREFIX + "McElieceKeyPairGeneratorSpi$McEliece");
+
+ provider.addAlgorithm("KeyPairGenerator." + PQCObjectIdentifiers.mcEliece, PREFIX + "McElieceKeyPairGeneratorSpi$McEliece");
+ provider.addAlgorithm("KeyPairGenerator." + PQCObjectIdentifiers.mcElieceCca2, PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
+
+ provider.addAlgorithm("Cipher.McEliecePointcheval", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA1", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA224", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval224");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA256", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval256");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA384", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval384");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA512", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval512");
+
+ provider.addAlgorithm("Cipher.McEliecePKCS", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA1", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA224", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS224");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA256", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS256");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA384", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS384");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA512", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS512");
+
+ provider.addAlgorithm("Cipher.McElieceKobaraImai", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA1", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA224", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai224");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA256", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai256");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA384", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai384");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA512", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai512");
+
+ provider.addAlgorithm("Cipher.McElieceFujisaki", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA1", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA224", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki224");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA256", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki256");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA384", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki384");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA512", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki512");
+
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/Rainbow.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/Rainbow.java
new file mode 100644
index 000000000..7752c4bff
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/Rainbow.java
@@ -0,0 +1,36 @@
+package org.spongycastle.pqc.jcajce.provider;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.spongycastle.pqc.jcajce.provider.rainbow.RainbowKeyFactorySpi;
+
+public class Rainbow
+{
+ private static final String PREFIX = "org.spongycastle.pqc.jcajce.provider" + ".rainbow.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.Rainbow", PREFIX + "RainbowKeyFactorySpi");
+ provider.addAlgorithm("KeyPairGenerator.Rainbow", PREFIX + "RainbowKeyPairGeneratorSpi");
+
+ addSignatureAlgorithm(provider, "SHA224", "Rainbow", PREFIX + "SignatureSpi$withSha224", PQCObjectIdentifiers.rainbowWithSha224);
+ addSignatureAlgorithm(provider, "SHA256", "Rainbow", PREFIX + "SignatureSpi$withSha256", PQCObjectIdentifiers.rainbowWithSha256);
+ addSignatureAlgorithm(provider, "SHA384", "Rainbow", PREFIX + "SignatureSpi$withSha384", PQCObjectIdentifiers.rainbowWithSha384);
+ addSignatureAlgorithm(provider, "SHA512", "Rainbow", PREFIX + "SignatureSpi$withSha512", PQCObjectIdentifiers.rainbowWithSha512);
+
+ AsymmetricKeyInfoConverter keyFact = new RainbowKeyFactorySpi();
+
+ registerOid(provider, PQCObjectIdentifiers.rainbow, "Rainbow", keyFact);
+ registerOidAlgorithmParameters(provider, PQCObjectIdentifiers.rainbow, "Rainbow");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java
new file mode 100644
index 000000000..b32531600
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java
@@ -0,0 +1,131 @@
+package org.spongycastle.pqc.jcajce.provider.gmss;
+
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.GMSSPublicKey;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.spongycastle.pqc.asn1.ParSet;
+import org.spongycastle.pqc.crypto.gmss.GMSSParameters;
+import org.spongycastle.pqc.crypto.gmss.GMSSPublicKeyParameters;
+import org.spongycastle.pqc.jcajce.provider.util.KeyUtil;
+import org.spongycastle.pqc.jcajce.spec.GMSSPublicKeySpec;
+import org.spongycastle.util.encoders.Hex;
+
+/**
+ * This class implements the GMSS public key and is usually initiated by the <a
+ * href="GMSSKeyPairGenerator">GMSSKeyPairGenerator</a>.
+ *
+ * @see org.spongycastle.pqc.crypto.gmss.GMSSKeyPairGenerator
+ * @see org.spongycastle.pqc.jcajce.spec.GMSSPublicKeySpec
+ */
+public class BCGMSSPublicKey
+ implements CipherParameters, PublicKey
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The GMSS public key
+ */
+ private byte[] publicKeyBytes;
+
+ /**
+ * The GMSSParameterSet
+ */
+ private GMSSParameters gmssParameterSet;
+
+
+ private GMSSParameters gmssParams;
+
+ /**
+ * The constructor
+ *
+ * @param pub a raw GMSS public key
+ * @param gmssParameterSet an instance of GMSS Parameterset
+ * @see org.spongycastle.pqc.crypto.gmss.GMSSKeyPairGenerator
+ */
+ public BCGMSSPublicKey(byte[] pub, GMSSParameters gmssParameterSet)
+ {
+ this.gmssParameterSet = gmssParameterSet;
+ this.publicKeyBytes = pub;
+ }
+
+ /**
+ * The constructor
+ *
+ * @param keySpec a GMSS key specification
+ */
+ protected BCGMSSPublicKey(GMSSPublicKeySpec keySpec)
+ {
+ this(keySpec.getPublicKey(), keySpec.getParameters());
+ }
+
+ public BCGMSSPublicKey(
+ GMSSPublicKeyParameters params)
+ {
+ this(params.getPublicKey(), params.getParameters());
+ }
+
+ /**
+ * Returns the name of the algorithm
+ *
+ * @return "GMSS"
+ */
+ public String getAlgorithm()
+ {
+ return "GMSS";
+ }
+
+ /**
+ * @return The GMSS public key byte array
+ */
+ public byte[] getPublicKeyBytes()
+ {
+ return publicKeyBytes;
+ }
+
+ /**
+ * @return The GMSS Parameterset
+ */
+ public GMSSParameters getParameterSet()
+ {
+ return gmssParameterSet;
+ }
+
+ /**
+ * Returns a human readable form of the GMSS public key
+ *
+ * @return A human readable form of the GMSS public key
+ */
+ public String toString()
+ {
+ String out = "GMSS public key : "
+ + new String(Hex.encode(publicKeyBytes)) + "\n"
+ + "Height of Trees: \n";
+
+ for (int i = 0; i < gmssParameterSet.getHeightOfTrees().length; i++)
+ {
+ out = out + "Layer " + i + " : "
+ + gmssParameterSet.getHeightOfTrees()[i]
+ + " WinternitzParameter: "
+ + gmssParameterSet.getWinternitzParameter()[i] + " K: "
+ + gmssParameterSet.getK()[i] + "\n";
+ }
+ return out;
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PQCObjectIdentifiers.gmss, new ParSet(gmssParameterSet.getNumOfLayers(), gmssParameterSet.getHeightOfTrees(), gmssParameterSet.getWinternitzParameter(), gmssParameterSet.getK()).toASN1Primitive()), new GMSSPublicKey(publicKeyBytes));
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java
new file mode 100644
index 000000000..0a22dd6f3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java
@@ -0,0 +1,307 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.McElieceCCA2PrivateKey;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2PrivateKeySpec;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.spongycastle.pqc.math.linearalgebra.GF2mField;
+import org.spongycastle.pqc.math.linearalgebra.Permutation;
+import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+/**
+ * This class implements a McEliece CCA2 private key and is usually instantiated
+ * by the {@link McElieceCCA2KeyPairGenerator} or {@link McElieceCCA2KeyFactorySpi}.
+ *
+ * @see McElieceCCA2KeyPairGenerator
+ */
+public class BCMcElieceCCA2PrivateKey
+ implements CipherParameters, PrivateKey
+{
+
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the dimension of the code, k>=n-mt
+ private int k;
+
+ // the finte field GF(2^m)
+ private GF2mField field;
+
+ // the irreducible Goppa polynomial
+ private PolynomialGF2mSmallM goppaPoly;
+
+ // the permutation
+ private Permutation p;
+
+ // the canonical check matrix
+ private GF2Matrix h;
+
+ // the matrix used to compute square roots in (GF(2^m))^t
+ private PolynomialGF2mSmallM[] qInv;
+
+ private McElieceCCA2Parameters mcElieceCCA2Params;
+
+ /**
+ * Constructor (used by the {@link McElieceCCA2KeyPairGenerator}).
+ *
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param field the field polynomial
+ * @param gp the irreducible Goppa polynomial
+ * @param p the permutation
+ * @param h the canonical check matrix
+ * @param qInv the matrix used to compute square roots in
+ * <tt>(GF(2^m))^t</tt>
+ */
+ public BCMcElieceCCA2PrivateKey(String oid, int n, int k, GF2mField field,
+ PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h,
+ PolynomialGF2mSmallM[] qInv)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ this.field = field;
+ this.goppaPoly = gp;
+ this.p = p;
+ this.h = h;
+ this.qInv = qInv;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceCCA2KeyFactorySpi}).
+ *
+ * @param keySpec a {@link McElieceCCA2PrivateKeySpec}
+ */
+ public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeySpec keySpec)
+ {
+ this(keySpec.getOIDString(), keySpec.getN(), keySpec.getK(), keySpec.getField(), keySpec
+ .getGoppaPoly(), keySpec.getP(), keySpec.getH(), keySpec
+ .getQInv());
+ }
+
+ public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeyParameters params)
+ {
+ this(params.getOIDString(), params.getN(), params.getK(), params.getField(), params.getGoppaPoly(),
+ params.getP(), params.getH(), params.getQInv());
+ this.mcElieceCCA2Params = params.getParameters();
+ }
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return "McEliece"
+ */
+ public String getAlgorithm()
+ {
+ return "McEliece";
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return k;
+ }
+
+ /**
+ * @return the degree of the Goppa polynomial (error correcting capability)
+ */
+ public int getT()
+ {
+ return goppaPoly.getDegree();
+ }
+
+ /**
+ * @return the finite field
+ */
+ public GF2mField getField()
+ {
+ return field;
+ }
+
+ /**
+ * @return the irreducible Goppa polynomial
+ */
+ public PolynomialGF2mSmallM getGoppaPoly()
+ {
+ return goppaPoly;
+ }
+
+ /**
+ * @return the permutation vector
+ */
+ public Permutation getP()
+ {
+ return p;
+ }
+
+ /**
+ * @return the canonical check matrix
+ */
+ public GF2Matrix getH()
+ {
+ return h;
+ }
+
+ /**
+ * @return the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
+ */
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ return qInv;
+ }
+
+ /**
+ * @return a human readable form of the key
+ */
+ public String toString()
+ {
+ String result = "";
+ result += " extension degree of the field : " + n + "\n";
+ result += " dimension of the code : " + k + "\n";
+ result += " irreducible Goppa polynomial : " + goppaPoly + "\n";
+ return result;
+ }
+
+ /**
+ * Compare this key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof BCMcElieceCCA2PrivateKey))
+ {
+ return false;
+ }
+
+ BCMcElieceCCA2PrivateKey otherKey = (BCMcElieceCCA2PrivateKey)other;
+
+ return (n == otherKey.n) && (k == otherKey.k)
+ && field.equals(otherKey.field)
+ && goppaPoly.equals(otherKey.goppaPoly) && p.equals(otherKey.p)
+ && h.equals(otherKey.h);
+ }
+
+ /**
+ * @return the hash code of this key
+ */
+ public int hashCode()
+ {
+ return k + n + field.hashCode() + goppaPoly.hashCode() + p.hashCode()
+ + h.hashCode();
+ }
+
+ /**
+ * @return the OID of the algorithm
+ */
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+ /**
+ * @return the OID to encode in the SubjectPublicKeyInfo structure
+ */
+ protected ASN1ObjectIdentifier getOID()
+ {
+ return new ASN1ObjectIdentifier(McElieceCCA2KeyFactorySpi.OID);
+ }
+
+ /**
+ * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
+ * structure
+ */
+ protected ASN1Primitive getAlgParams()
+ {
+ return null; // FIXME: needed at all?
+ }
+
+
+ /**
+ * Return the keyData to encode in the SubjectPublicKeyInfo structure.
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * McEliecePrivateKey ::= SEQUENCE {
+ * m INTEGER -- extension degree of the field
+ * k INTEGER -- dimension of the code
+ * field OCTET STRING -- field polynomial
+ * goppaPoly OCTET STRING -- irreducible Goppa polynomial
+ * p OCTET STRING -- permutation vector
+ * matrixH OCTET STRING -- canonical check matrix
+ * sqRootMatrix SEQUENCE OF OCTET STRING -- square root matrix
+ * }
+ * </pre>
+ *
+ * @return the keyData to encode in the SubjectPublicKeyInfo structure
+ */
+ public byte[] getEncoded()
+ {
+ McElieceCCA2PrivateKey privateKey = new McElieceCCA2PrivateKey(new ASN1ObjectIdentifier(oid), n, k, field, goppaPoly, p, h, qInv);
+ PrivateKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+ pki = new PrivateKeyInfo(algorithmIdentifier, privateKey);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ try
+ {
+ byte[] encoded = pki.getEncoded();
+ return encoded;
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public McElieceCCA2Parameters getMcElieceCCA2Parameters()
+ {
+ return mcElieceCCA2Params;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java
new file mode 100644
index 000000000..9c3361bca
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java
@@ -0,0 +1,227 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.McElieceCCA2PublicKey;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2PublicKeySpec;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+
+/**
+ * This class implements a McEliece CCA2 public key and is usually instantiated
+ * by the {@link McElieceCCA2KeyPairGenerator} or {@link McElieceCCA2KeyFactorySpi}.
+ */
+public class BCMcElieceCCA2PublicKey
+ implements CipherParameters, PublicKey
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the error correction capability of the code
+ private int t;
+
+ // the generator matrix
+ private GF2Matrix g;
+
+ private McElieceCCA2Parameters McElieceCCA2Params;
+
+ /**
+ * Constructor (used by the {@link McElieceCCA2KeyPairGenerator}).
+ *
+ * @param n the length of the code
+ * @param t the error correction capability of the code
+ * @param g the generator matrix
+ */
+ public BCMcElieceCCA2PublicKey(String oid, int n, int t, GF2Matrix g)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.g = g;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceCCA2KeyFactorySpi}).
+ *
+ * @param keySpec a {@link McElieceCCA2PublicKeySpec}
+ */
+ public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeySpec keySpec)
+ {
+ this(keySpec.getOIDString(), keySpec.getN(), keySpec.getT(), keySpec.getMatrixG());
+ }
+
+ public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeyParameters params)
+ {
+ this(params.getOIDString(), params.getN(), params.getT(), params.getMatrixG());
+ this.McElieceCCA2Params = params.getParameters();
+ }
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return "McEliece"
+ */
+ public String getAlgorithm()
+ {
+ return "McEliece";
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return g.getNumRows();
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getG()
+ {
+ return g;
+ }
+
+ /**
+ * @return a human readable form of the key
+ */
+ public String toString()
+ {
+ String result = "McEliecePublicKey:\n";
+ result += " length of the code : " + n + "\n";
+ result += " error correction capability: " + t + "\n";
+ result += " generator matrix : " + g.toString();
+ return result;
+ }
+
+ /**
+ * Compare this key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof BCMcElieceCCA2PublicKey))
+ {
+ return false;
+ }
+
+ BCMcElieceCCA2PublicKey otherKey = (BCMcElieceCCA2PublicKey)other;
+
+ return (n == otherKey.n) && (t == otherKey.t) && (g.equals(otherKey.g));
+ }
+
+ /**
+ * @return the hash code of this key
+ */
+ public int hashCode()
+ {
+ return n + t + g.hashCode();
+ }
+
+ /**
+ * @return the OID of the algorithm
+ */
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+ /**
+ * @return the OID to encode in the SubjectPublicKeyInfo structure
+ */
+ protected ASN1ObjectIdentifier getOID()
+ {
+ return new ASN1ObjectIdentifier(McElieceCCA2KeyFactorySpi.OID);
+ }
+
+ /**
+ * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
+ * structure
+ */
+ protected ASN1Primitive getAlgParams()
+ {
+ return null; // FIXME: needed at all?
+ }
+
+ /**
+ * Return the keyData to encode in the SubjectPublicKeyInfo structure.
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * McEliecePublicKey ::= SEQUENCE {
+ * n Integer -- length of the code
+ * t Integer -- error correcting capability
+ * matrixG OctetString -- generator matrix as octet string
+ * }
+ * </pre>
+ *
+ * @return the keyData to encode in the SubjectPublicKeyInfo structure
+ */
+ public byte[] getEncoded()
+ {
+ McElieceCCA2PublicKey key = new McElieceCCA2PublicKey(new ASN1ObjectIdentifier(oid), n, t, g);
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+
+ try
+ {
+ SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, key);
+
+ return subjectPublicKeyInfo.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+
+ }
+
+ public String getFormat()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public McElieceCCA2Parameters getMcElieceCCA2Parameters()
+ {
+ return McElieceCCA2Params;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java
new file mode 100644
index 000000000..21e778a49
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java
@@ -0,0 +1,334 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.McEliecePrivateKey;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.McEliecePrivateKeySpec;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.spongycastle.pqc.math.linearalgebra.GF2mField;
+import org.spongycastle.pqc.math.linearalgebra.Permutation;
+import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+/**
+ * This class implements a McEliece private key and is usually instantiated by
+ * the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}.
+ */
+public class BCMcEliecePrivateKey
+ implements CipherParameters, PrivateKey
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the dimension of the code, where <tt>k &gt;= n - mt</tt>
+ private int k;
+
+ // the underlying finite field
+ private GF2mField field;
+
+ // the irreducible Goppa polynomial
+ private PolynomialGF2mSmallM goppaPoly;
+
+ // the matrix S^-1
+ private GF2Matrix sInv;
+
+ // the permutation P1 used to generate the systematic check matrix
+ private Permutation p1;
+
+ // the permutation P2 used to compute the public generator matrix
+ private Permutation p2;
+
+ // the canonical check matrix of the code
+ private GF2Matrix h;
+
+ // the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
+ private PolynomialGF2mSmallM[] qInv;
+
+ private McElieceParameters mcElieceParams;
+
+
+ /**
+ * Constructor (used by the {@link McElieceKeyPairGenerator}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param field the field polynomial defining the finite field
+ * <tt>GF(2<sup>m</sup>)</tt>
+ * @param goppaPoly the irreducible Goppa polynomial
+ * @param sInv the matrix <tt>S<sup>-1</sup></tt>
+ * @param p1 the permutation used to generate the systematic check
+ * matrix
+ * @param p2 the permutation used to compute the public generator
+ * matrix
+ * @param h the canonical check matrix
+ * @param qInv the matrix used to compute square roots in
+ * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
+ */
+ public BCMcEliecePrivateKey(String oid, int n, int k, GF2mField field,
+ PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1,
+ Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ this.field = field;
+ this.goppaPoly = goppaPoly;
+ this.sInv = sInv;
+ this.p1 = p1;
+ this.p2 = p2;
+ this.h = h;
+ this.qInv = qInv;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceKeyFactorySpi}).
+ *
+ * @param keySpec a {@link McEliecePrivateKeySpec}
+ */
+ public BCMcEliecePrivateKey(McEliecePrivateKeySpec keySpec)
+ {
+ this(keySpec.getOIDString(), keySpec.getN(), keySpec.getK(), keySpec.getField(), keySpec
+ .getGoppaPoly(), keySpec.getSInv(), keySpec.getP1(), keySpec
+ .getP2(), keySpec.getH(), keySpec.getQInv());
+ }
+
+ public BCMcEliecePrivateKey(McEliecePrivateKeyParameters params)
+ {
+ this(params.getOIDString(), params.getN(), params.getK(), params.getField(), params.getGoppaPoly(),
+ params.getSInv(), params.getP1(), params.getP2(), params.getH(), params.getQInv());
+
+ this.mcElieceParams = params.getParameters();
+ }
+
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return "McEliece"
+ */
+ public String getAlgorithm()
+ {
+ return "McEliece";
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return k;
+ }
+
+ /**
+ * @return the finite field
+ */
+ public GF2mField getField()
+ {
+ return field;
+ }
+
+ /**
+ * @return the irreducible Goppa polynomial
+ */
+ public PolynomialGF2mSmallM getGoppaPoly()
+ {
+ return goppaPoly;
+ }
+
+ /**
+ * @return the k x k random binary non-singular matrix S
+ */
+ public GF2Matrix getSInv()
+ {
+ return sInv;
+ }
+
+ /**
+ * @return the permutation used to generate the systematic check matrix
+ */
+ public Permutation getP1()
+ {
+ return p1;
+ }
+
+ /**
+ * @return the permutation used to compute the public generator matrix
+ */
+ public Permutation getP2()
+ {
+ return p2;
+ }
+
+ /**
+ * @return the canonical check matrix
+ */
+ public GF2Matrix getH()
+ {
+ return h;
+ }
+
+ /**
+ * @return the matrix for computing square roots in <tt>(GF(2^m))^t</tt>
+ */
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ return qInv;
+ }
+
+ /**
+ * @return the OID of the algorithm
+ */
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+ /**
+ * @return a human readable form of the key
+ */
+ public String toString()
+ {
+ String result = " length of the code : " + n + "\n";
+ result += " dimension of the code : " + k + "\n";
+ result += " irreducible Goppa polynomial: " + goppaPoly + "\n";
+ result += " (k x k)-matrix S^-1 : " + sInv + "\n";
+ result += " permutation P1 : " + p1 + "\n";
+ result += " permutation P2 : " + p2;
+ return result;
+ }
+
+ /**
+ * Compare this key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (!(other instanceof BCMcEliecePrivateKey))
+ {
+ return false;
+ }
+ BCMcEliecePrivateKey otherKey = (BCMcEliecePrivateKey)other;
+
+ return (n == otherKey.n) && (k == otherKey.k)
+ && field.equals(otherKey.field)
+ && goppaPoly.equals(otherKey.goppaPoly)
+ && sInv.equals(otherKey.sInv) && p1.equals(otherKey.p1)
+ && p2.equals(otherKey.p2) && h.equals(otherKey.h);
+ }
+
+ /**
+ * @return the hash code of this key
+ */
+ public int hashCode()
+ {
+ return k + n + field.hashCode() + goppaPoly.hashCode()
+ + sInv.hashCode() + p1.hashCode() + p2.hashCode()
+ + h.hashCode();
+ }
+
+ /**
+ * @return the OID to encode in the SubjectPublicKeyInfo structure
+ */
+ protected ASN1ObjectIdentifier getOID()
+ {
+ return new ASN1ObjectIdentifier(McElieceKeyFactorySpi.OID);
+ }
+
+ /**
+ * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
+ * structure
+ */
+ protected ASN1Primitive getAlgParams()
+ {
+ return null; // FIXME: needed at all?
+ }
+
+ /**
+ * Return the key data to encode in the SubjectPublicKeyInfo structure.
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * McEliecePrivateKey ::= SEQUENCE {
+ * n INTEGER -- length of the code
+ * k INTEGER -- dimension of the code
+ * fieldPoly OCTET STRING -- field polynomial defining GF(2&circ;m)
+ * goppaPoly OCTET STRING -- irreducible Goppa polynomial
+ * sInv OCTET STRING -- matrix S&circ;-1
+ * p1 OCTET STRING -- permutation P1
+ * p2 OCTET STRING -- permutation P2
+ * h OCTET STRING -- canonical check matrix
+ * qInv SEQUENCE OF OCTET STRING -- matrix used to compute square roots
+ * }
+ * </pre>
+ *
+ * @return the key data to encode in the SubjectPublicKeyInfo structure
+ */
+ public byte[] getEncoded()
+ {
+ McEliecePrivateKey privateKey = new McEliecePrivateKey(new ASN1ObjectIdentifier(oid), n, k, field, goppaPoly, sInv, p1, p2, h, qInv);
+ PrivateKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+ pki = new PrivateKeyInfo(algorithmIdentifier, privateKey);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ try
+ {
+ byte[] encoded = pki.getEncoded();
+ return encoded;
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public McElieceParameters getMcElieceParameters()
+ {
+ return mcElieceParams;
+ }
+
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java
new file mode 100644
index 000000000..25c6fd149
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java
@@ -0,0 +1,231 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.McEliecePublicKey;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.McEliecePublicKeySpec;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+
+/**
+ * This class implements a McEliece public key and is usually instantiated by
+ * the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}.
+ */
+public class BCMcEliecePublicKey
+ implements CipherParameters, PublicKey
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ // the OID of the algorithm
+ private String oid;
+
+ /**
+ * the length of the code
+ */
+ private int n;
+
+ /**
+ * the error correction capability of the code
+ */
+ private int t;
+
+ /**
+ * the generator matrix
+ */
+ private GF2Matrix g;
+
+ private McElieceParameters McElieceParams;
+
+ /**
+ * Constructor (used by the {@link McElieceKeyPairGenerator}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param t the error correction capability of the code
+ * @param g the generator matrix
+ */
+ public BCMcEliecePublicKey(String oid, int n, int t, GF2Matrix g)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.g = g;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceKeyFactorySpi}).
+ *
+ * @param keySpec a {@link McEliecePublicKeySpec}
+ */
+ public BCMcEliecePublicKey(McEliecePublicKeySpec keySpec)
+ {
+ this(keySpec.getOIDString(), keySpec.getN(), keySpec.getT(), keySpec.getG());
+ }
+
+ public BCMcEliecePublicKey(McEliecePublicKeyParameters params)
+ {
+ this(params.getOIDString(), params.getN(), params.getT(), params.getG());
+ this.McElieceParams = params.getParameters();
+ }
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return "McEliece"
+ */
+ public String getAlgorithm()
+ {
+ return "McEliece";
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return g.getNumRows();
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getG()
+ {
+ return g;
+ }
+
+ /**
+ * @return a human readable form of the key
+ */
+ public String toString()
+ {
+ String result = "McEliecePublicKey:\n";
+ result += " length of the code : " + n + "\n";
+ result += " error correction capability: " + t + "\n";
+ result += " generator matrix : " + g.toString();
+ return result;
+ }
+
+ /**
+ * Compare this key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (!(other instanceof BCMcEliecePublicKey))
+ {
+ return false;
+ }
+ BCMcEliecePublicKey otherKey = (BCMcEliecePublicKey)other;
+
+ return (n == otherKey.n) && (t == otherKey.t) && g.equals(otherKey.g);
+ }
+
+ /**
+ * @return the hash code of this key
+ */
+ public int hashCode()
+ {
+ return n + t + g.hashCode();
+ }
+
+
+ /**
+ * @return the OID of the algorithm
+ */
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+ /**
+ * @return the OID to encode in the SubjectPublicKeyInfo structure
+ */
+ protected ASN1ObjectIdentifier getOID()
+ {
+ return new ASN1ObjectIdentifier(McElieceKeyFactorySpi.OID);
+ }
+
+ /**
+ * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
+ * structure
+ */
+ protected ASN1Primitive getAlgParams()
+ {
+ return null; // FIXME: needed at all?
+ }
+
+
+ /**
+ * Return the keyData to encode in the SubjectPublicKeyInfo structure.
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * McEliecePublicKey ::= SEQUENCE {
+ * n Integer -- length of the code
+ * t Integer -- error correcting capability
+ * matrixG OctetString -- generator matrix as octet string
+ * }
+ * </pre>
+ *
+ * @return the keyData to encode in the SubjectPublicKeyInfo structure
+ */
+ public byte[] getEncoded()
+ {
+ McEliecePublicKey key = new McEliecePublicKey(new ASN1ObjectIdentifier(oid), n, t, g);
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+
+ try
+ {
+ SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, key);
+
+ return subjectPublicKeyInfo.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public McElieceParameters getMcElieceParameters()
+ {
+ return McElieceParams;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java
new file mode 100644
index 000000000..d3de79bf8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java
@@ -0,0 +1,346 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+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 org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.pqc.asn1.McElieceCCA2PrivateKey;
+import org.spongycastle.pqc.asn1.McElieceCCA2PublicKey;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2PrivateKeySpec;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2PublicKeySpec;
+
+/**
+ * This class is used to translate between McEliece CCA2 keys and key
+ * specifications.
+ *
+ * @see BCMcElieceCCA2PrivateKey
+ * @see McElieceCCA2PrivateKeySpec
+ * @see BCMcElieceCCA2PublicKey
+ * @see McElieceCCA2PublicKeySpec
+ */
+public class McElieceCCA2KeyFactorySpi
+ extends KeyFactorySpi
+{
+
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2";
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCMcElieceCCA2PublicKey}. Currently, the following key
+ * specifications are supported: {@link McElieceCCA2PublicKeySpec},
+ * {@link X509EncodedKeySpec}.
+ *
+ * @param keySpec the key specification
+ * @return the McEliece CCA2 public key
+ * @throws InvalidKeySpecException if the key specification is not supported.
+ */
+ public PublicKey generatePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof McElieceCCA2PublicKeySpec)
+ {
+ return new BCMcElieceCCA2PublicKey(
+ (McElieceCCA2PublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof X509EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to X.509 from the spec
+ byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the SubjectPublicKeyInfo data structure to the pki object
+ SubjectPublicKeyInfo pki;
+ try
+ {
+ pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+
+
+ try
+ {
+ // --- Build and return the actual key.
+ ASN1Primitive innerType = pki.parsePublicKey();
+ ASN1Sequence publicKey = (ASN1Sequence)innerType;
+
+ // decode oidString (but we don't need it right now)
+ String oidString = ((ASN1ObjectIdentifier)publicKey.getObjectAt(0))
+ .toString();
+
+ // decode <n>
+ BigInteger bigN = ((ASN1Integer)publicKey.getObjectAt(1)).getValue();
+ int n = bigN.intValue();
+
+ // decode <t>
+ BigInteger bigT = ((ASN1Integer)publicKey.getObjectAt(2)).getValue();
+ int t = bigT.intValue();
+
+ // decode <matrixG>
+ byte[] matrixG = ((ASN1OctetString)publicKey.getObjectAt(3)).getOctets();
+
+ return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeySpec(
+ OID, n, t, matrixG));
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException(
+ "Unable to decode X509EncodedKeySpec: "
+ + cce.getMessage());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCMcElieceCCA2PrivateKey}. Currently, the following key
+ * specifications are supported: {@link McElieceCCA2PrivateKeySpec},
+ * {@link PKCS8EncodedKeySpec}.
+ *
+ * @param keySpec the key specification
+ * @return the McEliece CCA2 private key
+ * @throws InvalidKeySpecException if the KeySpec is not supported.
+ */
+ public PrivateKey generatePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof McElieceCCA2PrivateKeySpec)
+ {
+ return new BCMcElieceCCA2PrivateKey(
+ (McElieceCCA2PrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to PKCS#8 from the spec
+ byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the PKCS#8 data structure to the pki object
+ PrivateKeyInfo pki;
+
+ try
+ {
+ pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e);
+ }
+
+ try
+ {
+ // get the inner type inside the BIT STRING
+ ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
+
+ // build and return the actual key
+ ASN1Sequence privKey = (ASN1Sequence)innerType;
+
+ // decode oidString (but we don't need it right now)
+ String oidString = ((ASN1ObjectIdentifier)privKey.getObjectAt(0))
+ .toString();
+
+ // decode <n>
+ BigInteger bigN = ((ASN1Integer)privKey.getObjectAt(1)).getValue();
+ int n = bigN.intValue();
+
+ // decode <k>
+ BigInteger bigK = ((ASN1Integer)privKey.getObjectAt(2)).getValue();
+ int k = bigK.intValue();
+
+
+ // decode <fieldPoly>
+ byte[] encFieldPoly = ((ASN1OctetString)privKey.getObjectAt(3))
+ .getOctets();
+ // decode <goppaPoly>
+ byte[] encGoppaPoly = ((ASN1OctetString)privKey.getObjectAt(4))
+ .getOctets();
+ // decode <p>
+ byte[] encP = ((ASN1OctetString)privKey.getObjectAt(5)).getOctets();
+ // decode <h>
+ byte[] encH = ((ASN1OctetString)privKey.getObjectAt(6)).getOctets();
+ // decode <qInv>
+ ASN1Sequence qSeq = (ASN1Sequence)privKey.getObjectAt(7);
+ byte[][] encQInv = new byte[qSeq.size()][];
+ for (int i = 0; i < qSeq.size(); i++)
+ {
+ encQInv[i] = ((ASN1OctetString)qSeq.getObjectAt(i)).getOctets();
+ }
+
+ return new BCMcElieceCCA2PrivateKey(
+ new McElieceCCA2PrivateKeySpec(OID, n, k, encFieldPoly,
+ encGoppaPoly, encP, encH, encQInv));
+
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException(
+ "Unable to decode PKCS8EncodedKeySpec.");
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a given key into a key specification. Currently,
+ * the following key specifications are supported:
+ * <ul>
+ * <li>for McElieceCCA2PublicKey: {@link X509EncodedKeySpec},
+ * {@link McElieceCCA2PublicKeySpec}</li>
+ * <li>for McElieceCCA2PrivateKey: {@link PKCS8EncodedKeySpec},
+ * {@link McElieceCCA2PrivateKeySpec}</li>.
+ * </ul>
+ *
+ * @param key the key
+ * @param keySpec the key specification
+ * @return the specification of the McEliece CCA2 key
+ * @throws InvalidKeySpecException if the key type or the key specification is not
+ * supported.
+ * @see BCMcElieceCCA2PrivateKey
+ * @see McElieceCCA2PrivateKeySpec
+ * @see BCMcElieceCCA2PublicKey
+ * @see McElieceCCA2PublicKeySpec
+ */
+ public KeySpec getKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCMcElieceCCA2PrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (McElieceCCA2PrivateKeySpec.class
+ .isAssignableFrom(keySpec))
+ {
+ BCMcElieceCCA2PrivateKey privKey = (BCMcElieceCCA2PrivateKey)key;
+ return new McElieceCCA2PrivateKeySpec(OID, privKey.getN(), privKey
+ .getK(), privKey.getField(), privKey.getGoppaPoly(),
+ privKey.getP(), privKey.getH(), privKey.getQInv());
+ }
+ }
+ else if (key instanceof BCMcElieceCCA2PublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ else if (McElieceCCA2PublicKeySpec.class
+ .isAssignableFrom(keySpec))
+ {
+ BCMcElieceCCA2PublicKey pubKey = (BCMcElieceCCA2PublicKey)key;
+ return new McElieceCCA2PublicKeySpec(OID, pubKey.getN(), pubKey
+ .getT(), pubKey.getG());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ /**
+ * Translates a key into a form known by the FlexiProvider. Currently, only
+ * the following "source" keys are supported: {@link BCMcElieceCCA2PrivateKey},
+ * {@link BCMcElieceCCA2PublicKey}.
+ *
+ * @param key the key
+ * @return a key of a known key type
+ * @throws InvalidKeyException if the key type is not supported.
+ */
+ public Key translateKey(Key key)
+ throws InvalidKeyException
+ {
+ if ((key instanceof BCMcElieceCCA2PrivateKey)
+ || (key instanceof BCMcElieceCCA2PublicKey))
+ {
+ return key;
+ }
+ throw new InvalidKeyException("Unsupported key type.");
+
+ }
+
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo pki)
+ throws InvalidKeySpecException
+ {
+ // get the inner type inside the BIT STRING
+ try
+ {
+ ASN1Primitive innerType = pki.parsePublicKey();
+ McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance((ASN1Sequence)innerType);
+ return new BCMcElieceCCA2PublicKey(key.getOID().getId(), key.getN(), key.getT(), key.getG());
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException("Unable to decode X509EncodedKeySpec");
+ }
+ }
+
+
+ public PrivateKey generatePrivate(PrivateKeyInfo pki)
+ throws InvalidKeySpecException
+ {
+ // get the inner type inside the BIT STRING
+ try
+ {
+ ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
+ McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(innerType);
+ return new BCMcElieceCCA2PrivateKey(key.getOID().getId(), key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), key.getH(), key.getQInv());
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec");
+ }
+ }
+
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected KeySpec engineGetKeySpec(Key key, Class tClass)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java
new file mode 100644
index 000000000..a733d2a00
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java
@@ -0,0 +1,47 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca McElieceCCA2 objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class McElieceCCA2KeysToParams
+{
+
+
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMcElieceCCA2PublicKey)
+ {
+ BCMcElieceCCA2PublicKey k = (BCMcElieceCCA2PublicKey)key;
+
+ return new McElieceCCA2PublicKeyParameters(k.getOIDString(), k.getN(), k.getT(), k.getG(), k.getMcElieceCCA2Parameters());
+ }
+
+ throw new InvalidKeyException("can't identify McElieceCCA2 public key: " + key.getClass().getName());
+ }
+
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMcElieceCCA2PrivateKey)
+ {
+ BCMcElieceCCA2PrivateKey k = (BCMcElieceCCA2PrivateKey)key;
+ return new McElieceCCA2PrivateKeyParameters(k.getOIDString(), k.getN(), k.getK(), k.getField(), k.getGoppaPoly(),
+ k.getP(), k.getH(), k.getQInv(), k.getMcElieceCCA2Parameters());
+ }
+
+ throw new InvalidKeyException("can't identify McElieceCCA2 private key.");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java
new file mode 100644
index 000000000..a63c1852d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java
@@ -0,0 +1,131 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.spongycastle.pqc.math.linearalgebra.GF2Vector;
+import org.spongycastle.pqc.math.linearalgebra.GF2mField;
+import org.spongycastle.pqc.math.linearalgebra.GoppaCode;
+import org.spongycastle.pqc.math.linearalgebra.Permutation;
+import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.spongycastle.pqc.math.linearalgebra.Vector;
+
+/**
+ * Core operations for the CCA-secure variants of McEliece.
+ */
+public final class McElieceCCA2Primitives
+{
+
+ /**
+ * Default constructor (private).
+ */
+ private McElieceCCA2Primitives()
+ {
+ }
+
+ /**
+ * The McEliece encryption primitive.
+ *
+ * @param pubKey the public key
+ * @param m the message vector
+ * @param z the error vector
+ * @return <tt>m*G + z</tt>
+ */
+ public static GF2Vector encryptionPrimitive(BCMcElieceCCA2PublicKey pubKey,
+ GF2Vector m, GF2Vector z)
+ {
+
+ GF2Matrix matrixG = pubKey.getG();
+ Vector mG = matrixG.leftMultiplyLeftCompactForm(m);
+ return (GF2Vector)mG.add(z);
+ }
+
+ public static GF2Vector encryptionPrimitive(McElieceCCA2PublicKeyParameters pubKey,
+ GF2Vector m, GF2Vector z)
+ {
+
+ GF2Matrix matrixG = pubKey.getMatrixG();
+ Vector mG = matrixG.leftMultiplyLeftCompactForm(m);
+ return (GF2Vector)mG.add(z);
+ }
+
+ /**
+ * The McEliece decryption primitive.
+ *
+ * @param privKey the private key
+ * @param c the ciphertext vector <tt>c = m*G + z</tt>
+ * @return the message vector <tt>m</tt> and the error vector <tt>z</tt>
+ */
+ public static GF2Vector[] decryptionPrimitive(
+ BCMcElieceCCA2PrivateKey privKey, GF2Vector c)
+ {
+
+ // obtain values from private key
+ int k = privKey.getK();
+ Permutation p = privKey.getP();
+ GF2mField field = privKey.getField();
+ PolynomialGF2mSmallM gp = privKey.getGoppaPoly();
+ GF2Matrix h = privKey.getH();
+ PolynomialGF2mSmallM[] q = privKey.getQInv();
+
+ // compute inverse permutation P^-1
+ Permutation pInv = p.computeInverse();
+
+ // multiply c with permutation P^-1
+ GF2Vector cPInv = (GF2Vector)c.multiply(pInv);
+
+ // compute syndrome of cP^-1
+ GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv);
+
+ // decode syndrome
+ GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q);
+ GF2Vector mG = (GF2Vector)cPInv.add(errors);
+
+ // multiply codeword and error vector with P
+ mG = (GF2Vector)mG.multiply(p);
+ errors = (GF2Vector)errors.multiply(p);
+
+ // extract plaintext vector (last k columns of mG)
+ GF2Vector m = mG.extractRightVector(k);
+
+ // return vectors
+ return new GF2Vector[]{m, errors};
+ }
+
+ public static GF2Vector[] decryptionPrimitive(
+ McElieceCCA2PrivateKeyParameters privKey, GF2Vector c)
+ {
+
+ // obtain values from private key
+ int k = privKey.getK();
+ Permutation p = privKey.getP();
+ GF2mField field = privKey.getField();
+ PolynomialGF2mSmallM gp = privKey.getGoppaPoly();
+ GF2Matrix h = privKey.getH();
+ PolynomialGF2mSmallM[] q = privKey.getQInv();
+
+ // compute inverse permutation P^-1
+ Permutation pInv = p.computeInverse();
+
+ // multiply c with permutation P^-1
+ GF2Vector cPInv = (GF2Vector)c.multiply(pInv);
+
+ // compute syndrome of cP^-1
+ GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv);
+
+ // decode syndrome
+ GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q);
+ GF2Vector mG = (GF2Vector)cPInv.add(errors);
+
+ // multiply codeword and error vector with P
+ mG = (GF2Vector)mG.multiply(p);
+ errors = (GF2Vector)errors.multiply(p);
+
+ // extract plaintext vector (last k columns of mG)
+ GF2Vector m = mG.extractRightVector(k);
+
+ // return vectors
+ return new GF2Vector[]{m, errors};
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java
new file mode 100644
index 000000000..77e31c6ae
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java
@@ -0,0 +1,253 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceFujisakiCipher;
+import org.spongycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
+
+public class McElieceFujisakiCipherSpi
+ extends AsymmetricHybridCipher
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ // TODO digest needed?
+ private Digest digest;
+ private McElieceFujisakiCipher cipher;
+
+ /**
+ * buffer to store the input data
+ */
+ private ByteArrayOutputStream buf;
+
+
+ protected McElieceFujisakiCipherSpi(Digest digest, McElieceFujisakiCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ buf = new ByteArrayOutputStream();
+
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation.
+ *
+ * @param input byte array containing the next part of the input
+ * @param inOff index in the array where the input starts
+ * @param inLen length of the input
+ * @return the processed byte array.
+ */
+ public byte[] update(byte[] input, int inOff, int inLen)
+ {
+ buf.write(input, inOff, inLen);
+ return new byte[0];
+ }
+
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted, depending on
+ * how this cipher was initialized.
+ *
+ * @param input the input buffer
+ * @param inOff the offset in input where the input starts
+ * @param inLen the input length
+ * @return the new buffer with the result
+ * @throws BadPaddingException on deryption errors.
+ */
+ public byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws BadPaddingException
+ {
+ update(input, inOff, inLen);
+ byte[] data = buf.toByteArray();
+ buf.reset();
+ if (opMode == ENCRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageEncrypt(data);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageDecrypt(data);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ return null;
+ }
+
+
+ protected int encryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected int decryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom sr)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+
+ param = new ParametersWithRandom(param, sr);
+ digest.reset();
+ cipher.init(true, param);
+
+ }
+
+ protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ public String getName()
+ {
+ return "McElieceFujisakiCipher";
+ }
+
+ public int getKeySize(Key key)
+ throws InvalidKeyException
+ {
+ McElieceCCA2KeyParameters mcElieceCCA2KeyParameters;
+ if (key instanceof PublicKey)
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+ }
+ else
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ }
+
+
+ return cipher.getKeySize(mcElieceCCA2KeyParameters);
+ }
+
+ public byte[] messageEncrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageEncrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ public byte[] messageDecrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageDecrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+
+ static public class McElieceFujisaki
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki()
+ {
+ super(new SHA1Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+ static public class McElieceFujisaki224
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki224()
+ {
+ super(new SHA224Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+ static public class McElieceFujisaki256
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki256()
+ {
+ super(new SHA256Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+ static public class McElieceFujisaki384
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki384()
+ {
+ super(new SHA384Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+ static public class McElieceFujisaki512
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki512()
+ {
+ super(new SHA512Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java
new file mode 100644
index 000000000..1c2007a09
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java
@@ -0,0 +1,343 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+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 org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.pqc.asn1.McEliecePrivateKey;
+import org.spongycastle.pqc.asn1.McEliecePublicKey;
+import org.spongycastle.pqc.jcajce.spec.McEliecePrivateKeySpec;
+import org.spongycastle.pqc.jcajce.spec.McEliecePublicKeySpec;
+
+/**
+ * This class is used to translate between McEliece keys and key specifications.
+ *
+ * @see BCMcEliecePrivateKey
+ * @see McEliecePrivateKeySpec
+ * @see BCMcEliecePublicKey
+ * @see McEliecePublicKeySpec
+ */
+public class McElieceKeyFactorySpi
+ extends KeyFactorySpi
+{
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1";
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCMcEliecePublicKey}. Currently, the following key specifications
+ * are supported: {@link McEliecePublicKeySpec}, {@link X509EncodedKeySpec}.
+ *
+ * @param keySpec the key specification
+ * @return the McEliece public key
+ * @throws InvalidKeySpecException if the key specification is not supported.
+ */
+ public PublicKey generatePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof McEliecePublicKeySpec)
+ {
+ return new BCMcEliecePublicKey((McEliecePublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof X509EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to X.509 from the spec
+ byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the SubjectPublicKeyInfo data structure to the pki object
+ SubjectPublicKeyInfo pki;
+ try
+ {
+ pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+
+ try
+ {
+ // --- Build and return the actual key.
+ ASN1Primitive innerType = pki.parsePublicKey();
+ ASN1Sequence publicKey = (ASN1Sequence)innerType;
+
+ // decode oidString (but we don't need it right now)
+ String oidString = ((ASN1ObjectIdentifier)publicKey.getObjectAt(0))
+ .toString();
+
+ // decode <n>
+ BigInteger bigN = ((ASN1Integer)publicKey.getObjectAt(1)).getValue();
+ int n = bigN.intValue();
+
+ // decode <t>
+ BigInteger bigT = ((ASN1Integer)publicKey.getObjectAt(2)).getValue();
+ int t = bigT.intValue();
+
+ // decode <matrixG>
+ byte[] matrixG = ((ASN1OctetString)publicKey.getObjectAt(3)).getOctets();
+
+
+ return new BCMcEliecePublicKey(new McEliecePublicKeySpec(OID, t, n,
+ matrixG));
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException(
+ "Unable to decode X509EncodedKeySpec: "
+ + cce.getMessage());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCMcEliecePrivateKey}. Currently, the following key specifications
+ * are supported: {@link McEliecePrivateKeySpec},
+ * {@link PKCS8EncodedKeySpec}.
+ *
+ * @param keySpec the key specification
+ * @return the McEliece private key
+ * @throws InvalidKeySpecException if the KeySpec is not supported.
+ */
+ public PrivateKey generatePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof McEliecePrivateKeySpec)
+ {
+ return new BCMcEliecePrivateKey((McEliecePrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to PKCS#8 from the spec
+ byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the PKCS#8 data structure to the pki object
+ PrivateKeyInfo pki;
+
+ try
+ {
+ pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e);
+ }
+
+ try
+ {
+ ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
+
+ // build and return the actual key
+ ASN1Sequence privKey = (ASN1Sequence)innerType;
+
+ // decode oidString (but we don't need it right now)
+ String oidString = ((ASN1ObjectIdentifier)privKey.getObjectAt(0))
+ .toString();
+
+ // decode <n>
+ BigInteger bigN = ((ASN1Integer)privKey.getObjectAt(1)).getValue();
+ int n = bigN.intValue();
+
+ // decode <k>
+ BigInteger bigK = ((ASN1Integer)privKey.getObjectAt(2)).getValue();
+ int k = bigK.intValue();
+
+ // decode <fieldPoly>
+ byte[] encFieldPoly = ((ASN1OctetString)privKey.getObjectAt(3))
+ .getOctets();
+ // decode <goppaPoly>
+ byte[] encGoppaPoly = ((ASN1OctetString)privKey.getObjectAt(4))
+ .getOctets();
+
+ // decode <sInv>
+ byte[] encSInv = ((ASN1OctetString)privKey.getObjectAt(5)).getOctets();
+ // decode <p1>
+ byte[] encP1 = ((ASN1OctetString)privKey.getObjectAt(6)).getOctets();
+ // decode <p2>
+ byte[] encP2 = ((ASN1OctetString)privKey.getObjectAt(7)).getOctets();
+
+ //decode <h>
+ byte[] encH = ((ASN1OctetString)privKey.getObjectAt(8)).getOctets();
+
+ // decode <qInv>
+ ASN1Sequence qSeq = (ASN1Sequence)privKey.getObjectAt(9);
+ byte[][] encQInv = new byte[qSeq.size()][];
+ for (int i = 0; i < qSeq.size(); i++)
+ {
+ encQInv[i] = ((ASN1OctetString)qSeq.getObjectAt(i)).getOctets();
+ }
+
+ return new BCMcEliecePrivateKey(new McEliecePrivateKeySpec(OID, n, k,
+ encFieldPoly, encGoppaPoly, encSInv, encP1, encP2,
+ encH, encQInv));
+
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException(
+ "Unable to decode PKCS8EncodedKeySpec.");
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a given key into a key specification. Currently,
+ * the following key specifications are supported:
+ * <ul>
+ * <li>for McEliecePublicKey: {@link X509EncodedKeySpec},
+ * {@link McEliecePublicKeySpec}</li>
+ * <li>for McEliecePrivateKey: {@link PKCS8EncodedKeySpec},
+ * {@link McEliecePrivateKeySpec}</li>.
+ * </ul>
+ *
+ * @param key the key
+ * @param keySpec the key specification
+ * @return the specification of the McEliece key
+ * @throws InvalidKeySpecException if the key type or the key specification is not
+ * supported.
+ * @see BCMcEliecePrivateKey
+ * @see McEliecePrivateKeySpec
+ * @see BCMcEliecePublicKey
+ * @see McEliecePublicKeySpec
+ */
+ public KeySpec getKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCMcEliecePrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (McEliecePrivateKeySpec.class.isAssignableFrom(keySpec))
+ {
+ BCMcEliecePrivateKey privKey = (BCMcEliecePrivateKey)key;
+ return new McEliecePrivateKeySpec(OID, privKey.getN(), privKey
+ .getK(), privKey.getField(), privKey.getGoppaPoly(),
+ privKey.getSInv(), privKey.getP1(), privKey.getP2(),
+ privKey.getH(), privKey.getQInv());
+ }
+ }
+ else if (key instanceof BCMcEliecePublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ else if (McEliecePublicKeySpec.class.isAssignableFrom(keySpec))
+ {
+ BCMcEliecePublicKey pubKey = (BCMcEliecePublicKey)key;
+ return new McEliecePublicKeySpec(OID, pubKey.getN(), pubKey.getT(),
+ pubKey.getG());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ /**
+ * Translates a key into a form known by the FlexiProvider. Currently, only
+ * the following "source" keys are supported: {@link BCMcEliecePrivateKey},
+ * {@link BCMcEliecePublicKey}.
+ *
+ * @param key the key
+ * @return a key of a known key type
+ * @throws InvalidKeyException if the key type is not supported.
+ */
+ public Key translateKey(Key key)
+ throws InvalidKeyException
+ {
+ if ((key instanceof BCMcEliecePrivateKey)
+ || (key instanceof BCMcEliecePublicKey))
+ {
+ return key;
+ }
+ throw new InvalidKeyException("Unsupported key type.");
+
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo pki)
+ throws InvalidKeySpecException
+ {
+ // get the inner type inside the BIT STRING
+ try
+ {
+ ASN1Primitive innerType = pki.parsePublicKey();
+ McEliecePublicKey key = McEliecePublicKey.getInstance(innerType);
+ return new BCMcEliecePublicKey(key.getOID().getId(), key.getN(), key.getT(), key.getG());
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException("Unable to decode X509EncodedKeySpec");
+ }
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo pki)
+ throws InvalidKeySpecException
+ {
+ // get the inner type inside the BIT STRING
+ try
+ {
+ ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
+ McEliecePrivateKey key = McEliecePrivateKey.getInstance(innerType);
+ return new BCMcEliecePrivateKey(key.getOID().getId(), key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getSInv(), key.getP1(), key.getP2(), key.getH(), key.getQInv());
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec");
+ }
+ }
+
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected KeySpec engineGetKeySpec(Key key, Class tClass)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java
new file mode 100644
index 000000000..9e0115fd2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java
@@ -0,0 +1,146 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyGenerationParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2ParameterSpec;
+
+public abstract class McElieceKeyPairGeneratorSpi
+ extends KeyPairGenerator
+{
+ public McElieceKeyPairGeneratorSpi(
+ String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ /**
+ *
+ *
+ *
+ */
+
+ public static class McElieceCCA2
+ extends McElieceKeyPairGeneratorSpi
+ {
+
+ McElieceCCA2KeyPairGenerator kpg;
+
+
+ public McElieceCCA2()
+ {
+ super("McElieceCCA-2");
+ }
+
+ public McElieceCCA2(String s)
+ {
+ super(s);
+ }
+
+ public void initialize(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException
+ {
+ kpg = new McElieceCCA2KeyPairGenerator();
+ super.initialize(params);
+ ECCKeyGenParameterSpec ecc = (ECCKeyGenParameterSpec)params;
+
+ McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters(new SecureRandom(), new McElieceCCA2Parameters(ecc.getM(), ecc.getT()));
+ kpg.init(mccca2KGParams);
+ }
+
+ public void initialize(int keySize, SecureRandom random)
+ {
+ McElieceCCA2ParameterSpec paramSpec = new McElieceCCA2ParameterSpec();
+
+ // call the initializer with the chosen parameters
+ try
+ {
+ this.initialize(paramSpec);
+ }
+ catch (InvalidAlgorithmParameterException ae)
+ {
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair();
+ McElieceCCA2PrivateKeyParameters sk = (McElieceCCA2PrivateKeyParameters)generateKeyPair.getPrivate();
+ McElieceCCA2PublicKeyParameters pk = (McElieceCCA2PublicKeyParameters)generateKeyPair.getPublic();
+
+ return new KeyPair(new BCMcElieceCCA2PublicKey(pk), new BCMcElieceCCA2PrivateKey(sk));
+
+ }
+
+ }
+
+ /**
+ *
+ *
+ *
+ */
+
+ public static class McEliece
+ extends McElieceKeyPairGeneratorSpi
+ {
+
+ McElieceKeyPairGenerator kpg;
+
+
+ public McEliece()
+ {
+ super("McEliece");
+ }
+
+ public void initialize(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException
+ {
+ kpg = new McElieceKeyPairGenerator();
+ super.initialize(params);
+ ECCKeyGenParameterSpec ecc = (ECCKeyGenParameterSpec)params;
+
+ McElieceKeyGenerationParameters mccKGParams = new McElieceKeyGenerationParameters(new SecureRandom(), new McElieceParameters(ecc.getM(), ecc.getT()));
+ kpg.init(mccKGParams);
+ }
+
+ public void initialize(int keySize, SecureRandom random)
+ {
+ ECCKeyGenParameterSpec paramSpec = new ECCKeyGenParameterSpec();
+
+ // call the initializer with the chosen parameters
+ try
+ {
+ this.initialize(paramSpec);
+ }
+ catch (InvalidAlgorithmParameterException ae)
+ {
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair();
+ McEliecePrivateKeyParameters sk = (McEliecePrivateKeyParameters)generateKeyPair.getPrivate();
+ McEliecePublicKeyParameters pk = (McEliecePublicKeyParameters)generateKeyPair.getPublic();
+
+ return new KeyPair(new BCMcEliecePublicKey(pk), new BCMcEliecePrivateKey(sk));
+ }
+
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java
new file mode 100644
index 000000000..649d1d458
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java
@@ -0,0 +1,47 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca McEliece objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class McElieceKeysToParams
+{
+
+
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMcEliecePublicKey)
+ {
+ BCMcEliecePublicKey k = (BCMcEliecePublicKey)key;
+
+ return new McEliecePublicKeyParameters(k.getOIDString(), k.getN(), k.getT(), k.getG(), k.getMcElieceParameters());
+ }
+
+ throw new InvalidKeyException("can't identify McEliece public key: " + key.getClass().getName());
+ }
+
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMcEliecePrivateKey)
+ {
+ BCMcEliecePrivateKey k = (BCMcEliecePrivateKey)key;
+ return new McEliecePrivateKeyParameters(k.getOIDString(), k.getN(), k.getK(), k.getField(), k.getGoppaPoly(),
+ k.getSInv(), k.getP1(), k.getP2(), k.getH(), k.getQInv(), k.getMcElieceParameters());
+ }
+
+ throw new InvalidKeyException("can't identify McEliece private key.");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java
new file mode 100644
index 000000000..60e77a5cd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java
@@ -0,0 +1,307 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKobaraImaiCipher;
+import org.spongycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
+
+public class McElieceKobaraImaiCipherSpi
+ extends AsymmetricHybridCipher
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+
+ // TODO digest needed?
+ private Digest digest;
+ private McElieceKobaraImaiCipher cipher;
+
+ /**
+ * buffer to store the input data
+ */
+ private ByteArrayOutputStream buf = new ByteArrayOutputStream();
+
+
+ public McElieceKobaraImaiCipherSpi()
+ {
+ buf = new ByteArrayOutputStream();
+ }
+
+ protected McElieceKobaraImaiCipherSpi(Digest digest, McElieceKobaraImaiCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ buf = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation.
+ *
+ * @param input byte array containing the next part of the input
+ * @param inOff index in the array where the input starts
+ * @param inLen length of the input
+ * @return the processed byte array.
+ */
+ public byte[] update(byte[] input, int inOff, int inLen)
+ {
+ buf.write(input, inOff, inLen);
+ return new byte[0];
+ }
+
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted, depending on
+ * how this cipher was initialized.
+ *
+ * @param input the input buffer
+ * @param inOff the offset in input where the input starts
+ * @param inLen the input length
+ * @return the new buffer with the result
+ * @throws BadPaddingException if this cipher is in decryption mode, and (un)padding has
+ * been requested, but the decrypted data is not bounded by
+ * the appropriate padding bytes
+ */
+ public byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws BadPaddingException
+ {
+ update(input, inOff, inLen);
+ if (opMode == ENCRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageEncrypt(this.pad());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+ byte[] inputOfDecr = buf.toByteArray();
+ buf.reset();
+
+ try
+ {
+ return unpad(cipher.messageDecrypt(inputOfDecr));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ return null;
+ }
+
+ protected int encryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected int decryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom sr)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+
+ buf.reset();
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+
+ param = new ParametersWithRandom(param, sr);
+ digest.reset();
+ cipher.init(true, param);
+ }
+
+ protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+
+ buf.reset();
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ public String getName()
+ {
+ return "McElieceKobaraImaiCipher";
+ }
+
+ public int getKeySize(Key key)
+ throws InvalidKeyException
+ {
+ McElieceCCA2KeyParameters mcElieceCCA2KeyParameters;
+ if (key instanceof PublicKey)
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+ return cipher.getKeySize(mcElieceCCA2KeyParameters);
+ }
+ else if (key instanceof PrivateKey)
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+ return cipher.getKeySize(mcElieceCCA2KeyParameters);
+ }
+ else
+ {
+ throw new InvalidKeyException();
+ }
+
+
+ }
+
+ /**
+ * Pad and return the message stored in the message buffer.
+ *
+ * @return the padded message
+ */
+ private byte[] pad()
+ {
+ buf.write(0x01);
+ byte[] result = buf.toByteArray();
+ buf.reset();
+ return result;
+ }
+
+ /**
+ * Unpad a message.
+ *
+ * @param pmBytes the padded message
+ * @return the message
+ * @throws BadPaddingException if the padded message is invalid.
+ */
+ private byte[] unpad(byte[] pmBytes)
+ throws BadPaddingException
+ {
+ // find first non-zero byte
+ int index;
+ for (index = pmBytes.length - 1; index >= 0 && pmBytes[index] == 0; index--)
+ {
+ ;
+ }
+
+ // check if padding byte is valid
+ if (pmBytes[index] != 0x01)
+ {
+ throw new BadPaddingException("invalid ciphertext");
+ }
+
+ // extract and return message
+ byte[] mBytes = new byte[index];
+ System.arraycopy(pmBytes, 0, mBytes, 0, index);
+ return mBytes;
+ }
+
+
+ public byte[] messageEncrypt()
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageEncrypt((this.pad()));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ public byte[] messageDecrypt()
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ byte[] inputOfDecr = buf.toByteArray();
+ buf.reset();
+ try
+ {
+ output = unpad(cipher.messageDecrypt(inputOfDecr));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ static public class McElieceKobaraImai
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai()
+ {
+ super(new SHA1Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+ static public class McElieceKobaraImai224
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai224()
+ {
+ super(new SHA224Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+ static public class McElieceKobaraImai256
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai256()
+ {
+ super(new SHA256Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+ static public class McElieceKobaraImai384
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai384()
+ {
+ super(new SHA384Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+ static public class McElieceKobaraImai512
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai512()
+ {
+ super(new SHA512Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java
new file mode 100644
index 000000000..cbabfdcc3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java
@@ -0,0 +1,171 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePKCSCipher;
+import org.spongycastle.pqc.jcajce.provider.util.AsymmetricBlockCipher;
+
+public class McEliecePKCSCipherSpi
+ extends AsymmetricBlockCipher
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ // TODO digest needed?
+ private Digest digest;
+ private McEliecePKCSCipher cipher;
+
+ public McEliecePKCSCipherSpi(Digest digest, McEliecePKCSCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ }
+
+ protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom sr)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+
+ CipherParameters param;
+ param = McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key);
+
+ param = new ParametersWithRandom(param, sr);
+ digest.reset();
+ cipher.init(true, param);
+ this.maxPlainTextSize = cipher.maxPlainTextSize;
+ this.cipherTextSize = cipher.cipherTextSize;
+ }
+
+ protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+ param = McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ digest.reset();
+ cipher.init(false, param);
+ this.maxPlainTextSize = cipher.maxPlainTextSize;
+ this.cipherTextSize = cipher.cipherTextSize;
+ }
+
+ protected byte[] messageEncrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageEncrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+ protected byte[] messageDecrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageDecrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+ public String getName()
+ {
+ return "McEliecePKCS";
+ }
+
+ public int getKeySize(Key key)
+ throws InvalidKeyException
+ {
+ McElieceKeyParameters mcElieceKeyParameters;
+ if (key instanceof PublicKey)
+ {
+ mcElieceKeyParameters = (McElieceKeyParameters)McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key);
+ }
+ else
+ {
+ mcElieceKeyParameters = (McElieceKeyParameters)McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ }
+
+
+ return cipher.getKeySize(mcElieceKeyParameters);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+
+ static public class McEliecePKCS
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS()
+ {
+ super(new SHA1Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+ static public class McEliecePKCS224
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS224()
+ {
+ super(new SHA224Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+ static public class McEliecePKCS256
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS256()
+ {
+ super(new SHA256Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+ static public class McEliecePKCS384
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS384()
+ {
+ super(new SHA384Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+ static public class McEliecePKCS512
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS512()
+ {
+ super(new SHA512Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java
new file mode 100644
index 000000000..314b7a304
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java
@@ -0,0 +1,247 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePointchevalCipher;
+import org.spongycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
+
+public class McEliecePointchevalCipherSpi
+ extends AsymmetricHybridCipher
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ // TODO digest needed?
+ private Digest digest;
+ private McEliecePointchevalCipher cipher;
+
+ /**
+ * buffer to store the input data
+ */
+ private ByteArrayOutputStream buf = new ByteArrayOutputStream();
+
+
+ protected McEliecePointchevalCipherSpi(Digest digest, McEliecePointchevalCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ buf = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation.
+ *
+ * @param input byte array containing the next part of the input
+ * @param inOff index in the array where the input starts
+ * @param inLen length of the input
+ * @return the processed byte array.
+ */
+ public byte[] update(byte[] input, int inOff, int inLen)
+ {
+ buf.write(input, inOff, inLen);
+ return new byte[0];
+ }
+
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted, depending on
+ * how this cipher was initialized.
+ *
+ * @param input the input buffer
+ * @param inOff the offset in input where the input starts
+ * @param inLen the input length
+ * @return the new buffer with the result
+ * @throws BadPaddingException on deryption errors.
+ */
+ public byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws BadPaddingException
+ {
+ update(input, inOff, inLen);
+ byte[] data = buf.toByteArray();
+ buf.reset();
+ if (opMode == ENCRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageEncrypt(data);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageDecrypt(data);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ return null;
+ }
+
+ protected int encryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected int decryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom sr)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+
+ param = new ParametersWithRandom(param, sr);
+ digest.reset();
+ cipher.init(true, param);
+ }
+
+ protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ public String getName()
+ {
+ return "McEliecePointchevalCipher";
+ }
+
+
+ public int getKeySize(Key key)
+ throws InvalidKeyException
+ {
+ McElieceCCA2KeyParameters mcElieceCCA2KeyParameters;
+ if (key instanceof PublicKey)
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+ }
+ else
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+ }
+
+ return cipher.getKeySize(mcElieceCCA2KeyParameters);
+ }
+
+ public byte[] messageEncrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageEncrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ public byte[] messageDecrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageDecrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////77
+
+ static public class McEliecePointcheval
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval()
+ {
+ super(new SHA1Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+ static public class McEliecePointcheval224
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval224()
+ {
+ super(new SHA224Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+ static public class McEliecePointcheval256
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval256()
+ {
+ super(new SHA256Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+ static public class McEliecePointcheval384
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval384()
+ {
+ super(new SHA384Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+ static public class McEliecePointcheval512
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval512()
+ {
+ super(new SHA512Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java
new file mode 100644
index 000000000..114d20095
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java
@@ -0,0 +1,243 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.util.Arrays;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.spongycastle.pqc.asn1.RainbowPrivateKey;
+import org.spongycastle.pqc.crypto.rainbow.Layer;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters;
+import org.spongycastle.pqc.crypto.rainbow.util.RainbowUtil;
+import org.spongycastle.pqc.jcajce.spec.RainbowPrivateKeySpec;
+
+/**
+ * The Private key in Rainbow consists of the linear affine maps L1, L2 and the
+ * map F, consisting of quadratic polynomials. In this implementation, we
+ * denote: L1 = A1*x + b1 L2 = A2*x + b2
+ * <p/>
+ * The coefficients of the polynomials in F are stored in 3-dimensional arrays
+ * per layer. The indices of these arrays denote the polynomial, and the
+ * variables.
+ * <p/>
+ * More detailed information about the private key is to be found in the paper
+ * of Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable Polynomial
+ * Signature Scheme. ACNS 2005: 164-175 (http://dx.doi.org/10.1007/11496137_12)
+ */
+public class BCRainbowPrivateKey
+ implements PrivateKey
+{
+ private static final long serialVersionUID = 1L;
+
+ // the inverse of L1
+ private short[][] A1inv;
+
+ // translation vector element of L1
+ private short[] b1;
+
+ // the inverse of L2
+ private short[][] A2inv;
+
+ // translation vector of L2
+ private short[] b2;
+
+ /*
+ * components of F
+ */
+ private Layer[] layers;
+
+ // set of vinegar vars per layer.
+ private int[] vi;
+
+
+ /**
+ * Constructor.
+ *
+ * @param A1inv
+ * @param b1
+ * @param A2inv
+ * @param b2
+ * @param layers
+ */
+ public BCRainbowPrivateKey(short[][] A1inv, short[] b1, short[][] A2inv,
+ short[] b2, int[] vi, Layer[] layers)
+ {
+ this.A1inv = A1inv;
+ this.b1 = b1;
+ this.A2inv = A2inv;
+ this.b2 = b2;
+ this.vi = vi;
+ this.layers = layers;
+ }
+
+ /**
+ * Constructor (used by the {@link RainbowKeyFactorySpi}).
+ *
+ * @param keySpec a {@link RainbowPrivateKeySpec}
+ */
+ public BCRainbowPrivateKey(RainbowPrivateKeySpec keySpec)
+ {
+ this(keySpec.getInvA1(), keySpec.getB1(), keySpec.getInvA2(), keySpec
+ .getB2(), keySpec.getVi(), keySpec.getLayers());
+ }
+
+ public BCRainbowPrivateKey(
+ RainbowPrivateKeyParameters params)
+ {
+ this(params.getInvA1(), params.getB1(), params.getInvA2(), params.getB2(), params.getVi(), params.getLayers());
+ }
+
+ /**
+ * Getter for the inverse matrix of A1.
+ *
+ * @return the A1inv inverse
+ */
+ public short[][] getInvA1()
+ {
+ return this.A1inv;
+ }
+
+ /**
+ * Getter for the translation part of the private quadratic map L1.
+ *
+ * @return b1 the translation part of L1
+ */
+ public short[] getB1()
+ {
+ return this.b1;
+ }
+
+ /**
+ * Getter for the translation part of the private quadratic map L2.
+ *
+ * @return b2 the translation part of L2
+ */
+ public short[] getB2()
+ {
+ return this.b2;
+ }
+
+ /**
+ * Getter for the inverse matrix of A2
+ *
+ * @return the A2inv
+ */
+ public short[][] getInvA2()
+ {
+ return this.A2inv;
+ }
+
+ /**
+ * Returns the layers contained in the private key
+ *
+ * @return layers
+ */
+ public Layer[] getLayers()
+ {
+ return this.layers;
+ }
+
+ /**
+ * Returns the array of vi-s
+ *
+ * @return the vi
+ */
+ public int[] getVi()
+ {
+ return vi;
+ }
+
+ /**
+ * Compare this Rainbow private key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof BCRainbowPrivateKey))
+ {
+ return false;
+ }
+ BCRainbowPrivateKey otherKey = (BCRainbowPrivateKey)other;
+
+ boolean eq = true;
+ // compare using shortcut rule ( && instead of &)
+ eq = eq && RainbowUtil.equals(A1inv, otherKey.getInvA1());
+ eq = eq && RainbowUtil.equals(A2inv, otherKey.getInvA2());
+ eq = eq && RainbowUtil.equals(b1, otherKey.getB1());
+ eq = eq && RainbowUtil.equals(b2, otherKey.getB2());
+ eq = eq && Arrays.equals(vi, otherKey.getVi());
+ if (layers.length != otherKey.getLayers().length)
+ {
+ return false;
+ }
+ for (int i = layers.length - 1; i >= 0; i--)
+ {
+ eq &= layers[i].equals(otherKey.getLayers()[i]);
+ }
+ return eq;
+ }
+
+ public int hashCode()
+ {
+ int hash = layers.length;
+
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(A1inv);
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(b1);
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(A2inv);
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(b2);
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(vi);
+
+ for (int i = layers.length - 1; i >= 0; i--)
+ {
+ hash = hash * 37 + layers[i].hashCode();
+ }
+
+
+ return hash;
+ }
+
+ /**
+ * @return name of the algorithm - "Rainbow"
+ */
+ public final String getAlgorithm()
+ {
+ return "Rainbow";
+ }
+
+ public byte[] getEncoded()
+ {
+ RainbowPrivateKey privateKey = new RainbowPrivateKey(A1inv, b1, A2inv, b2, vi, layers);
+
+ PrivateKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.rainbow, DERNull.INSTANCE);
+ pki = new PrivateKeyInfo(algorithmIdentifier, privateKey);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ try
+ {
+ byte[] encoded = pki.getEncoded();
+ return encoded;
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java
new file mode 100644
index 000000000..12f16ed9a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java
@@ -0,0 +1,170 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.spongycastle.pqc.asn1.RainbowPublicKey;
+import org.spongycastle.pqc.crypto.rainbow.RainbowParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters;
+import org.spongycastle.pqc.crypto.rainbow.util.RainbowUtil;
+import org.spongycastle.pqc.jcajce.provider.util.KeyUtil;
+import org.spongycastle.pqc.jcajce.spec.RainbowPublicKeySpec;
+import org.spongycastle.util.Arrays;
+
+/**
+ * This class implements CipherParameters and PublicKey.
+ * <p/>
+ * The public key in Rainbow consists of n - v1 polynomial components of the
+ * private key's F and the field structure of the finite field k.
+ * <p/>
+ * The quadratic (or mixed) coefficients of the polynomials from the public key
+ * are stored in the 2-dimensional array in lexicographical order, requiring n *
+ * (n + 1) / 2 entries for each polynomial. The singular terms are stored in a
+ * 2-dimensional array requiring n entries per polynomial, the scalar term of
+ * each polynomial is stored in a 1-dimensional array.
+ * <p/>
+ * More detailed information on the public key is to be found in the paper of
+ * Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable Polynomial
+ * Signature Scheme. ACNS 2005: 164-175 (http://dx.doi.org/10.1007/11496137_12)
+ */
+public class BCRainbowPublicKey
+ implements PublicKey
+{
+ private static final long serialVersionUID = 1L;
+
+ private short[][] coeffquadratic;
+ private short[][] coeffsingular;
+ private short[] coeffscalar;
+ private int docLength; // length of possible document to sign
+
+ private RainbowParameters rainbowParams;
+
+ /**
+ * Constructor
+ *
+ * @param docLength
+ * @param coeffQuadratic
+ * @param coeffSingular
+ * @param coeffScalar
+ */
+ public BCRainbowPublicKey(int docLength,
+ short[][] coeffQuadratic, short[][] coeffSingular,
+ short[] coeffScalar)
+ {
+ this.docLength = docLength;
+ this.coeffquadratic = coeffQuadratic;
+ this.coeffsingular = coeffSingular;
+ this.coeffscalar = coeffScalar;
+ }
+
+ /**
+ * Constructor (used by the {@link RainbowKeyFactorySpi}).
+ *
+ * @param keySpec a {@link RainbowPublicKeySpec}
+ */
+ public BCRainbowPublicKey(RainbowPublicKeySpec keySpec)
+ {
+ this(keySpec.getDocLength(), keySpec.getCoeffQuadratic(), keySpec
+ .getCoeffSingular(), keySpec.getCoeffScalar());
+ }
+
+ public BCRainbowPublicKey(
+ RainbowPublicKeyParameters params)
+ {
+ this(params.getDocLength(), params.getCoeffQuadratic(), params.getCoeffSingular(), params.getCoeffScalar());
+ }
+
+ /**
+ * @return the docLength
+ */
+ public int getDocLength()
+ {
+ return this.docLength;
+ }
+
+ /**
+ * @return the coeffQuadratic
+ */
+ public short[][] getCoeffQuadratic()
+ {
+ return coeffquadratic;
+ }
+
+ /**
+ * @return the coeffSingular
+ */
+ public short[][] getCoeffSingular()
+ {
+ short[][] copy = new short[coeffsingular.length][];
+
+ for (int i = 0; i != coeffsingular.length; i++)
+ {
+ copy[i] = Arrays.clone(coeffsingular[i]);
+ }
+
+ return copy;
+ }
+
+
+ /**
+ * @return the coeffScalar
+ */
+ public short[] getCoeffScalar()
+ {
+ return Arrays.clone(coeffscalar);
+ }
+
+ /**
+ * Compare this Rainbow public key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof BCRainbowPublicKey))
+ {
+ return false;
+ }
+ BCRainbowPublicKey otherKey = (BCRainbowPublicKey)other;
+
+ return docLength == otherKey.getDocLength()
+ && RainbowUtil.equals(coeffquadratic, otherKey.getCoeffQuadratic())
+ && RainbowUtil.equals(coeffsingular, otherKey.getCoeffSingular())
+ && RainbowUtil.equals(coeffscalar, otherKey.getCoeffScalar());
+ }
+
+ public int hashCode()
+ {
+ int hash = docLength;
+
+ hash = hash * 37 + Arrays.hashCode(coeffquadratic);
+ hash = hash * 37 + Arrays.hashCode(coeffsingular);
+ hash = hash * 37 + Arrays.hashCode(coeffscalar);
+
+ return hash;
+ }
+
+ /**
+ * @return name of the algorithm - "Rainbow"
+ */
+ public final String getAlgorithm()
+ {
+ return "Rainbow";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ RainbowPublicKey key = new RainbowPublicKey(docLength, coeffquadratic, coeffsingular, coeffscalar);
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.rainbow, DERNull.INSTANCE);
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, key);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java
new file mode 100644
index 000000000..614e07965
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java
@@ -0,0 +1,236 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.io.IOException;
+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 org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.spongycastle.pqc.asn1.RainbowPrivateKey;
+import org.spongycastle.pqc.asn1.RainbowPublicKey;
+import org.spongycastle.pqc.jcajce.spec.RainbowPrivateKeySpec;
+import org.spongycastle.pqc.jcajce.spec.RainbowPublicKeySpec;
+
+
+/**
+ * This class transforms Rainbow keys and Rainbow key specifications.
+ *
+ * @see BCRainbowPublicKey
+ * @see RainbowPublicKeySpec
+ * @see BCRainbowPrivateKey
+ * @see RainbowPrivateKeySpec
+ */
+public class RainbowKeyFactorySpi
+ extends KeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCRainbowPrivateKey}. Currently, the following key specifications
+ * are supported: {@link RainbowPrivateKeySpec}, {@link PKCS8EncodedKeySpec}.
+ * <p/>
+ * <p/>
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * RainbowPrivateKey ::= SEQUENCE {
+ * oid OBJECT IDENTIFIER -- OID identifying the algorithm
+ * A1inv SEQUENCE OF OCTET STRING -- inversed matrix of L1
+ * b1 OCTET STRING -- translation vector of L1
+ * A2inv SEQUENCE OF OCTET STRING -- inversed matrix of L2
+ * b2 OCTET STRING -- translation vector of L2
+ * vi OCTET STRING -- num of elmts in each Set S
+ * layers SEQUENCE OF Layer -- layers of F
+ * }
+ *
+ * Layer ::= SEQUENCE OF Poly
+ * Poly ::= SEQUENCE {
+ * alpha SEQUENCE OF OCTET STRING
+ * beta SEQUENCE OF OCTET STRING
+ * gamma OCTET STRING
+ * eta OCTET
+ * }
+ * </pre>
+ * <p/>
+ * <p/>
+ *
+ * @param keySpec the key specification
+ * @return the Rainbow private key
+ * @throws InvalidKeySpecException if the KeySpec is not supported.
+ */
+ public PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof RainbowPrivateKeySpec)
+ {
+ return new BCRainbowPrivateKey((RainbowPrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to PKCS#8 from the spec
+ byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
+
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCRainbowPublicKey}. Currently, the following key specifications are
+ * supported:{@link X509EncodedKeySpec}.
+ * <p/>
+ * <p/>
+ * <p/>
+ * The ASN.1 definition of a public key's structure is
+ * <p/>
+ * <pre>
+ * RainbowPublicKey ::= SEQUENCE {
+ * oid OBJECT IDENTIFIER -- OID identifying the algorithm
+ * docLength Integer -- length of signable msg
+ * coeffquadratic SEQUENCE OF OCTET STRING -- quadratic (mixed) coefficients
+ * coeffsingular SEQUENCE OF OCTET STRING -- singular coefficients
+ * coeffscalar OCTET STRING -- scalar coefficients
+ * }
+ * </pre>
+ * <p/>
+ * <p/>
+ *
+ * @param keySpec the key specification
+ * @return the Rainbow public key
+ * @throws InvalidKeySpecException if the KeySpec is not supported.
+ */
+ public PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof RainbowPublicKeySpec)
+ {
+ return new BCRainbowPublicKey((RainbowPublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof X509EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to X.509 from the spec
+ byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the SubjectPublicKeyInfo data structure to the pki object
+ try
+ {
+ return generatePublic(SubjectPublicKeyInfo.getInstance(encKey));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: " + keySpec + ".");
+ }
+
+ /**
+ * Converts a given key into a key specification, if possible. Currently the
+ * following specs are supported:
+ * <ul>
+ * <li>for RainbowPublicKey: X509EncodedKeySpec, RainbowPublicKeySpec
+ * <li>for RainbowPrivateKey: PKCS8EncodedKeySpec, RainbowPrivateKeySpec
+ * </ul>
+ *
+ * @param key the key
+ * @param keySpec the key specification
+ * @return the specification of the CMSS key
+ * @throws InvalidKeySpecException if the key type or key specification is not supported.
+ */
+ public final KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCRainbowPrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (RainbowPrivateKeySpec.class.isAssignableFrom(keySpec))
+ {
+ BCRainbowPrivateKey privKey = (BCRainbowPrivateKey)key;
+ return new RainbowPrivateKeySpec(privKey.getInvA1(), privKey
+ .getB1(), privKey.getInvA2(), privKey.getB2(), privKey
+ .getVi(), privKey.getLayers());
+ }
+ }
+ else if (key instanceof BCRainbowPublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ else if (RainbowPublicKeySpec.class.isAssignableFrom(keySpec))
+ {
+ BCRainbowPublicKey pubKey = (BCRainbowPublicKey)key;
+ return new RainbowPublicKeySpec(pubKey.getDocLength(), pubKey
+ .getCoeffQuadratic(), pubKey.getCoeffSingular(), pubKey
+ .getCoeffScalar());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ /**
+ * Translates a key into a form known by the FlexiProvider. Currently the
+ * following key types are supported: RainbowPrivateKey, RainbowPublicKey.
+ *
+ * @param key the key
+ * @return a key of a known key type
+ * @throws InvalidKeyException if the key is not supported.
+ */
+ public final Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCRainbowPrivateKey || key instanceof BCRainbowPublicKey)
+ {
+ return key;
+ }
+
+ throw new InvalidKeyException("Unsupported key type");
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ RainbowPrivateKey pKey = RainbowPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+ return new BCRainbowPrivateKey(pKey.getInvA1(), pKey.getB1(), pKey.getInvA2(), pKey.getB2(), pKey.getVi(), pKey.getLayers());
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ RainbowPublicKey pKey = RainbowPublicKey.getInstance(keyInfo.parsePublicKey());
+
+ return new BCRainbowPublicKey(pKey.getDocLength(), pKey.getCoeffQuadratic(), pKey.getCoeffSingular(), pKey.getCoeffScalar());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java
new file mode 100644
index 000000000..82239575e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java
@@ -0,0 +1,72 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.pqc.crypto.rainbow.RainbowKeyGenerationParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowKeyPairGenerator;
+import org.spongycastle.pqc.crypto.rainbow.RainbowParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.RainbowParameterSpec;
+
+public class RainbowKeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ RainbowKeyGenerationParameters param;
+ RainbowKeyPairGenerator engine = new RainbowKeyPairGenerator();
+ int strength = 1024;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public RainbowKeyPairGeneratorSpi()
+ {
+ super("Rainbow");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof RainbowParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a RainbowParameterSpec");
+ }
+ RainbowParameterSpec rainbowParams = (RainbowParameterSpec)params;
+
+ param = new RainbowKeyGenerationParameters(random, new RainbowParameters(rainbowParams.getVi()));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ param = new RainbowKeyGenerationParameters(random, new RainbowParameters(new RainbowParameterSpec().getVi()));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ RainbowPublicKeyParameters pub = (RainbowPublicKeyParameters)pair.getPublic();
+ RainbowPrivateKeyParameters priv = (RainbowPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCRainbowPublicKey(pub),
+ new BCRainbowPrivateKey(priv));
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeysToParams.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeysToParams.java
new file mode 100644
index 000000000..0ae006efb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeysToParams.java
@@ -0,0 +1,49 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters;
+
+
+/**
+ * utility class for converting jce/jca Rainbow objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+
+public class RainbowKeysToParams
+{
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCRainbowPublicKey)
+ {
+ BCRainbowPublicKey k = (BCRainbowPublicKey)key;
+
+ return new RainbowPublicKeyParameters(k.getDocLength(), k.getCoeffQuadratic(),
+ k.getCoeffSingular(), k.getCoeffScalar());
+ }
+
+ throw new InvalidKeyException("can't identify Rainbow public key: " + key.getClass().getName());
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCRainbowPrivateKey)
+ {
+ BCRainbowPrivateKey k = (BCRainbowPrivateKey)key;
+ return new RainbowPrivateKeyParameters(k.getInvA1(), k.getB1(),
+ k.getInvA2(), k.getB2(), k.getVi(), k.getLayers());
+ }
+
+ throw new InvalidKeyException("can't identify Rainbow private key.");
+ }
+}
+
+
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java
new file mode 100644
index 000000000..01b126992
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java
@@ -0,0 +1,164 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.rainbow.RainbowSigner;
+
+/**
+ * Rainbow Signature class, extending the jce SignatureSpi.
+ */
+public class SignatureSpi
+ extends java.security.SignatureSpi
+{
+ private Digest digest;
+ private RainbowSigner signer;
+ private SecureRandom random;
+
+ protected SignatureSpi(Digest digest, RainbowSigner signer)
+ {
+ this.digest = digest;
+ this.signer = signer;
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+ param = RainbowKeysToParams.generatePublicKeyParameter(publicKey);
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+ param = RainbowKeysToParams.generatePrivateKeyParameter(privateKey);
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ digest.reset();
+ signer.init(true, param);
+
+ }
+
+ protected void engineUpdate(byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+ try
+ {
+ byte[] sig = signer.generateSignature(hash);
+
+ return sig;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+ return signer.verifySignature(hash, sigBytes);
+ }
+
+ protected void engineSetParameter(AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href =
+ * "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)"
+ * >
+ */
+ protected void engineSetParameter(String param, Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+
+ static public class withSha224
+ extends SignatureSpi
+ {
+ public withSha224()
+ {
+ super(new SHA224Digest(), new RainbowSigner());
+ }
+ }
+
+ static public class withSha256
+ extends SignatureSpi
+ {
+ public withSha256()
+ {
+ super(new SHA256Digest(), new RainbowSigner());
+ }
+ }
+
+ static public class withSha384
+ extends SignatureSpi
+ {
+ public withSha384()
+ {
+ super(new SHA384Digest(), new RainbowSigner());
+ }
+ }
+
+ static public class withSha512
+ extends SignatureSpi
+ {
+ public withSha512()
+ {
+ super(new SHA512Digest(), new RainbowSigner());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java
new file mode 100644
index 000000000..2e5678ad6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java
@@ -0,0 +1,522 @@
+package org.spongycastle.pqc.jcajce.provider.util;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+
+
+/**
+ * The AsymmetricBlockCipher class extends CipherSpiExt.
+ * NOTE: Some Ciphers are using Padding. OneAndZeroesPadding is used as default
+ * padding. However padding can still be specified, but mode is not supported;
+ * if you try to instantiate the cipher with something else than "NONE" as mode
+ * NoSuchAlgorithmException is thrown.
+ */
+public abstract class AsymmetricBlockCipher
+ extends CipherSpiExt
+{
+
+ /**
+ * ParameterSpec used with this cipher
+ */
+ protected AlgorithmParameterSpec paramSpec;
+
+ /**
+ * Internal buffer
+ */
+ protected ByteArrayOutputStream buf;
+
+ /**
+ * The maximum number of bytes the cipher can decrypt.
+ */
+ protected int maxPlainTextSize;
+
+ /**
+ * The maximum number of bytes the cipher can encrypt.
+ */
+ protected int cipherTextSize;
+
+ /**
+ * The AsymmetricBlockCipher() constructor
+ */
+ public AsymmetricBlockCipher()
+ {
+ buf = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Return the block size (in bytes). Note: although the ciphers extending
+ * this class are not block ciphers, the method was adopted to return the
+ * maximal plaintext and ciphertext sizes for non hybrid ciphers. If the
+ * cipher is hybrid, it returns 0.
+ *
+ * @return if the cipher is not a hybrid one the max plain/cipher text size
+ * is returned, otherwise 0 is returned
+ */
+ public final int getBlockSize()
+ {
+ return opMode == ENCRYPT_MODE ? maxPlainTextSize : cipherTextSize;
+ }
+
+ /**
+ * @return <tt>null</tt> since no initialization vector is used.
+ */
+ public final byte[] getIV()
+ {
+ return null;
+ }
+
+ /**
+ * Return the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next update or doFinal operation, given
+ * the input length <tt>inLen</tt> (in bytes). This call takes into
+ * account any unprocessed (buffered) data from a previous update call, and
+ * padding. The actual output length of the next update() or doFinal() call
+ * may be smaller than the length returned by this method.
+ * <p/>
+ * If the input length plus the length of the buffered data exceeds the
+ * maximum length, <tt>0</tt> is returned.
+ *
+ * @param inLen the length of the input
+ * @return the length of the ciphertext or <tt>0</tt> if the input is too
+ * long.
+ */
+ public final int getOutputSize(int inLen)
+ {
+
+ int totalLen = inLen + buf.size();
+
+ int maxLen = getBlockSize();
+
+ if (totalLen > maxLen)
+ {
+ // the length of the input exceeds the maximal supported length
+ return 0;
+ }
+
+ return maxLen;
+ }
+
+ /**
+ * <p/>
+ * Returns the parameters used with this cipher.
+ * <p/>
+ * The returned parameters may be the same that were used to initialize this
+ * cipher, or may contain the default set of parameters or a set of randomly
+ * generated parameters used by the underlying cipher implementation
+ * (provided that the underlying cipher implementation uses a default set of
+ * parameters or creates new parameters if it needs parameters but was not
+ * initialized with any).
+ * <p/>
+ *
+ * @return the parameters used with this cipher, or null if this cipher does
+ * not use any parameters.
+ */
+ public final AlgorithmParameterSpec getParameters()
+ {
+ return paramSpec;
+ }
+
+ /**
+ * Initializes the cipher for encryption by forwarding it to
+ * initEncrypt(Key, FlexiSecureRandom).
+ * <p/>
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * @param key the encryption or decryption key.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ */
+ public final void initEncrypt(Key key)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initEncrypt(key, null, new SecureRandom());
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initialize this cipher for encryption by forwarding it to
+ * initEncrypt(Key, FlexiSecureRandom, AlgorithmParameterSpec).
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * @param key the encryption or decryption key.
+ * @param random the source of randomness.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ */
+ public final void initEncrypt(Key key, SecureRandom random)
+ throws InvalidKeyException
+ {
+
+ try
+ {
+ initEncrypt(key, null, random);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initializes the cipher for encryption by forwarding it to
+ * initEncrypt(Key, FlexiSecureRandom, AlgorithmParameterSpec).
+ *
+ * @param key the encryption or decryption key.
+ * @param params the algorithm parameters.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidAlgorithmParameterException if the given algortihm parameters are inappropriate for
+ * this cipher, or if this cipher is being initialized for
+ * decryption and requires algorithm parameters and params
+ * is null.
+ */
+ public final void initEncrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initEncrypt(key, params, new SecureRandom());
+ }
+
+ /**
+ * This method initializes the AsymmetricBlockCipher with a certain key for
+ * data encryption.
+ * <p/>
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ * <p/>
+ * Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it
+ * <p/>
+ *
+ * @param key the key which has to be used to encrypt data.
+ * @param secureRandom the source of randomness.
+ * @param params the algorithm parameters.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is being initialized for
+ * decryption and requires algorithm parameters and params
+ * is null.
+ */
+ public final void initEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom secureRandom)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+ opMode = ENCRYPT_MODE;
+ initCipherEncrypt(key, params, secureRandom);
+ }
+
+ /**
+ * Initialize the cipher for decryption by forwarding it to
+ * {@link #initDecrypt(Key, AlgorithmParameterSpec)}.
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * @param key the encryption or decryption key.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ */
+ public final void initDecrypt(Key key)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initDecrypt(key, null);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * This method initializes the AsymmetricBlockCipher with a certain key for
+ * data decryption.
+ * <p/>
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ * <p/>
+ * Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it
+ * <p/>
+ *
+ * @param key the key which has to be used to decrypt data.
+ * @param params the algorithm parameters.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is being initialized for
+ * decryption and requires algorithm parameters and params
+ * is null.
+ */
+ public final void initDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ opMode = DECRYPT_MODE;
+ initCipherDecrypt(key, params);
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation. This method
+ * just writes the input into an internal buffer.
+ *
+ * @param input byte array containing the next part of the input
+ * @param inOff index in the array where the input starts
+ * @param inLen length of the input
+ * @return a new buffer with the result (always empty)
+ */
+ public final byte[] update(byte[] input, int inOff, int inLen)
+ {
+ if (inLen != 0)
+ {
+ buf.write(input, inOff, inLen);
+ }
+ return new byte[0];
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the output buffer
+ * @param outOff the offset where the result is stored
+ * @return the length of the output (always 0)
+ */
+ public final int update(byte[] input, int inOff, int inLen, byte[] output,
+ int outOff)
+ {
+ update(input, inOff, inLen);
+ return 0;
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result
+ * @throws IllegalBlockSizeException if the plaintext or ciphertext size is too large.
+ * @throws BadPaddingException if the ciphertext is invalid.
+ */
+ public final byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+
+ checkLength(inLen);
+ update(input, inOff, inLen);
+ byte[] mBytes = buf.toByteArray();
+ buf.reset();
+
+ switch (opMode)
+ {
+ case ENCRYPT_MODE:
+ return messageEncrypt(mBytes);
+
+ case DECRYPT_MODE:
+ return messageDecrypt(mBytes);
+
+ default:
+ return null;
+
+ }
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the buffer for the result
+ * @param outOff the offset where the result is stored
+ * @return the output length
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ * @throws IllegalBlockSizeException if the plaintext or ciphertext size is too large.
+ * @throws BadPaddingException if the ciphertext is invalid.
+ */
+ public final int doFinal(byte[] input, int inOff, int inLen, byte[] output,
+ int outOff)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException
+ {
+
+ if (output.length < getOutputSize(inLen))
+ {
+ throw new ShortBufferException("Output buffer too short.");
+ }
+
+ byte[] out = doFinal(input, inOff, inLen);
+ System.arraycopy(out, 0, output, outOff, out.length);
+ return out.length;
+ }
+
+ /**
+ * Since asymmetric block ciphers do not support modes, this method does
+ * nothing.
+ *
+ * @param modeName the cipher mode (unused)
+ */
+ protected final void setMode(String modeName)
+ {
+ // empty
+ }
+
+ /**
+ * Since asymmetric block ciphers do not support padding, this method does
+ * nothing.
+ *
+ * @param paddingName the name of the padding scheme (not used)
+ */
+ protected final void setPadding(String paddingName)
+ {
+ // empty
+ }
+
+ /**
+ * Check if the message length plus the length of the input length can be
+ * en/decrypted. This method uses the specific values
+ * {@link #maxPlainTextSize} and {@link #cipherTextSize} which are set by
+ * the implementations. If the input length plus the length of the internal
+ * buffer is greater than {@link #maxPlainTextSize} for encryption or not
+ * equal to {@link #cipherTextSize} for decryption, an
+ * {@link IllegalBlockSizeException} will be thrown.
+ *
+ * @param inLen length of the input to check
+ * @throws IllegalBlockSizeException if the input length is invalid.
+ */
+ protected void checkLength(int inLen)
+ throws IllegalBlockSizeException
+ {
+
+ int inLength = inLen + buf.size();
+
+ if (opMode == ENCRYPT_MODE)
+ {
+ if (inLength > maxPlainTextSize)
+ {
+ throw new IllegalBlockSizeException(
+ "The length of the plaintext (" + inLength
+ + " bytes) is not supported by "
+ + "the cipher (max. " + maxPlainTextSize
+ + " bytes).");
+ }
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+ if (inLength != cipherTextSize)
+ {
+ throw new IllegalBlockSizeException(
+ "Illegal ciphertext length (expected " + cipherTextSize
+ + " bytes, was " + inLength + " bytes).");
+ }
+ }
+
+ }
+
+ /**
+ * Initialize the AsymmetricBlockCipher with a certain key for data
+ * encryption.
+ *
+ * @param key the key which has to be used to encrypt data
+ * @param params the algorithm parameters
+ * @param sr the source of randomness
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for
+ * initializing this cipher.
+ */
+ protected abstract void initCipherEncrypt(Key key,
+ AlgorithmParameterSpec params, SecureRandom sr)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Initialize the AsymmetricBlockCipher with a certain key for data
+ * encryption.
+ *
+ * @param key the key which has to be used to decrypt data
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for
+ * initializing this cipher.
+ */
+ protected abstract void initCipherDecrypt(Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException;
+
+ /**
+ * Encrypt the message stored in input. The method should also perform an
+ * additional length check.
+ *
+ * @param input the message to be encrypted (usually the message length is
+ * less than or equal to maxPlainTextSize)
+ * @return the encrypted message (it has length equal to maxCipherTextSize_)
+ * @throws IllegalBlockSizeException if the input is inappropriate for this cipher.
+ * @throws BadPaddingException if the input format is invalid.
+ */
+ protected abstract byte[] messageEncrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException;
+
+ /**
+ * Decrypt the ciphertext stored in input. The method should also perform an
+ * additional length check.
+ *
+ * @param input the ciphertext to be decrypted (the ciphertext length is
+ * less than or equal to maxCipherTextSize)
+ * @return the decrypted message
+ * @throws IllegalBlockSizeException if the input is inappropriate for this cipher.
+ * @throws BadPaddingException if the input format is invalid.
+ */
+ protected abstract byte[] messageDecrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException;
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricHybridCipher.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricHybridCipher.java
new file mode 100644
index 000000000..57d367b28
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricHybridCipher.java
@@ -0,0 +1,397 @@
+package org.spongycastle.pqc.jcajce.provider.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.ShortBufferException;
+
+/**
+ * The AsymmetricHybridCipher class extends CipherSpiExt.
+ * NOTE: Some Ciphers are using Padding. OneAndZeroesPadding is used as default
+ * padding. However padding can still be specified, but mode is not supported;
+ * if you try to instantiate the cipher with something else than "NONE" as mode,
+ * NoSuchAlgorithmException is thrown.
+ */
+public abstract class AsymmetricHybridCipher
+ extends CipherSpiExt
+{
+
+ /**
+ * ParameterSpec used with this cipher
+ */
+ protected AlgorithmParameterSpec paramSpec;
+
+ /**
+ * Since asymmetric hybrid ciphers do not support modes, this method does
+ * nothing.
+ *
+ * @param modeName the cipher mode (unused)
+ */
+ protected final void setMode(String modeName)
+ {
+ // empty
+ }
+
+ /**
+ * Since asymmetric hybrid ciphers do not support padding, this method does
+ * nothing.
+ *
+ * @param paddingName the name of the padding scheme (not used)
+ */
+ protected final void setPadding(String paddingName)
+ {
+ // empty
+ }
+
+ /**
+ * @return <tt>null</tt> since no initialization vector is used.
+ */
+ public final byte[] getIV()
+ {
+ return null;
+ }
+
+ /**
+ * @return 0 since the implementing algorithms are not block ciphers
+ */
+ public final int getBlockSize()
+ {
+ return 0;
+ }
+
+ /**
+ * Return the parameters used with this cipher.
+ * <p/>
+ * The returned parameters may be the same that were used to initialize this
+ * cipher, or may contain the default set of parameters or a set of randomly
+ * generated parameters used by the underlying cipher implementation
+ * (provided that the underlying cipher implementation uses a default set of
+ * parameters or creates new parameters if it needs parameters but was not
+ * initialized with any).
+ *
+ * @return the parameters used with this cipher, or <tt>null</tt> if this
+ * cipher does not use any parameters.
+ */
+ public final AlgorithmParameterSpec getParameters()
+ {
+ return paramSpec;
+ }
+
+ /**
+ * Return the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next update or doFinal operation, given
+ * the input length <tt>inLen</tt> (in bytes). This call takes into
+ * account any unprocessed (buffered) data from a previous update call, and
+ * padding. The actual output length of the next update() or doFinal() call
+ * may be smaller than the length returned by this method.
+ *
+ * @param inLen the length of the input
+ * @return the length of the output of the next <tt>update()</tt> or
+ * <tt>doFinal()</tt> call
+ */
+ public final int getOutputSize(int inLen)
+ {
+ return opMode == ENCRYPT_MODE ? encryptOutputSize(inLen)
+ : decryptOutputSize(inLen);
+ }
+
+ /**
+ * Initialize the cipher for encryption by forwarding it to
+ * {@link #initEncrypt(Key, AlgorithmParameterSpec, SecureRandom)}.
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using {@link #getParameters()}.
+ *
+ * @param key the encryption key
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidParameterException if this cipher needs algorithm parameters for
+ * initialization and cannot generate parameters itself.
+ */
+ public final void initEncrypt(Key key)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initEncrypt(key, null, new SecureRandom());
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initialize this cipher for encryption by forwarding it to
+ * {@link #initEncrypt(Key, AlgorithmParameterSpec, SecureRandom)}.
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using {@link #getParameters()}.
+ *
+ * @param key the encryption key
+ * @param random the source of randomness
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidParameterException if this cipher needs algorithm parameters for
+ * initialization and cannot generate parameters itself.
+ */
+ public final void initEncrypt(Key key, SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initEncrypt(key, null, random);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initialize the cipher for encryption by forwarding it to initEncrypt(Key,
+ * FlexiSecureRandom, AlgorithmParameterSpec).
+ *
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is initialized with
+ * <tt>null</tt> parameters and cannot generate parameters
+ * itself.
+ */
+ public final void initEncrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initEncrypt(key, params, new SecureRandom());
+ }
+
+ /**
+ * Initialize the cipher with a certain key for data encryption.
+ * <p/>
+ * If this cipher requires any random bytes (e.g., for parameter
+ * generation), it will get them from <tt>random</tt>.
+ * <p/>
+ * Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it.
+ *
+ * @param key the encryption key
+ * @param random the source of randomness
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is initialized with
+ * <tt>null</tt> parameters and cannot generate parameters
+ * itself.
+ */
+ public final void initEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+ opMode = ENCRYPT_MODE;
+ initCipherEncrypt(key, params, random);
+ }
+
+ /**
+ * Initialize the cipher for decryption by forwarding it to initDecrypt(Key,
+ * FlexiSecureRandom).
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using {@link #getParameters()}.
+ *
+ * @param key the decryption key
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ */
+ public final void initDecrypt(Key key)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initDecrypt(key, null);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initialize the cipher with a certain key for data decryption.
+ * <p/>
+ * If this cipher requires any random bytes (e.g., for parameter
+ * generation), it will get them from <tt>random</tt>.
+ * <p/>
+ * Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it
+ *
+ * @param key the decryption key
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is initialized with
+ * <tt>null</tt> parameters and cannot generate parameters
+ * itself.
+ */
+ public final void initDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ opMode = DECRYPT_MODE;
+ initCipherDecrypt(key, params);
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result (maybe an empty byte array)
+ */
+ public abstract byte[] update(byte[] input, int inOff, int inLen);
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the output buffer
+ * @param outOff the offset where the result is stored
+ * @return the length of the output
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ */
+ public final int update(byte[] input, int inOff, int inLen, byte[] output,
+ int outOff)
+ throws ShortBufferException
+ {
+ if (output.length < getOutputSize(inLen))
+ {
+ throw new ShortBufferException("output");
+ }
+ byte[] out = update(input, inOff, inLen);
+ System.arraycopy(out, 0, output, outOff, out.length);
+ return out.length;
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result
+ * @throws BadPaddingException if the ciphertext is invalid.
+ */
+ public abstract byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws BadPaddingException;
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the buffer for the result
+ * @param outOff the offset where the result is stored
+ * @return the output length
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ * @throws BadPaddingException if the ciphertext is invalid.
+ */
+ public final int doFinal(byte[] input, int inOff, int inLen, byte[] output,
+ int outOff)
+ throws ShortBufferException, BadPaddingException
+ {
+
+ if (output.length < getOutputSize(inLen))
+ {
+ throw new ShortBufferException("Output buffer too short.");
+ }
+ byte[] out = doFinal(input, inOff, inLen);
+ System.arraycopy(out, 0, output, outOff, out.length);
+ return out.length;
+ }
+
+ /**
+ * Compute the output size of an update() or doFinal() operation of a hybrid
+ * asymmetric cipher in encryption mode when given input of the specified
+ * length.
+ *
+ * @param inLen the length of the input
+ * @return the output size
+ */
+ protected abstract int encryptOutputSize(int inLen);
+
+ /**
+ * Compute the output size of an update() or doFinal() operation of a hybrid
+ * asymmetric cipher in decryption mode when given input of the specified
+ * length.
+ *
+ * @param inLen the length of the input
+ * @return the output size
+ */
+ protected abstract int decryptOutputSize(int inLen);
+
+ /**
+ * Initialize the AsymmetricHybridCipher with a certain key for data
+ * encryption.
+ *
+ * @param key the key which has to be used to encrypt data
+ * @param params the algorithm parameters
+ * @param sr the source of randomness
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for
+ * initializing this cipher.
+ */
+ protected abstract void initCipherEncrypt(Key key,
+ AlgorithmParameterSpec params, SecureRandom sr)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Initialize the AsymmetricHybridCipher with a certain key for data
+ * encryption.
+ *
+ * @param key the key which has to be used to decrypt data
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for
+ * initializing this cipher.
+ */
+ protected abstract void initCipherDecrypt(Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException;
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/CipherSpiExt.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/CipherSpiExt.java
new file mode 100644
index 000000000..7978e2aee
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/CipherSpiExt.java
@@ -0,0 +1,635 @@
+package org.spongycastle.pqc.jcajce.provider.util;
+
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+
+/**
+ * The CipherSpiExt class extends CipherSpi.
+ */
+public abstract class CipherSpiExt
+ extends CipherSpi
+{
+
+ /**
+ * Constant specifying encrypt mode.
+ */
+ public static final int ENCRYPT_MODE = javax.crypto.Cipher.ENCRYPT_MODE;
+
+ /**
+ * Constant specifying decrypt mode.
+ */
+ public static final int DECRYPT_MODE = javax.crypto.Cipher.DECRYPT_MODE;
+
+ /**
+ * The operation mode for this cipher ({@link #ENCRYPT_MODE} or
+ * {@link #DECRYPT_MODE}).
+ */
+ protected int opMode;
+
+ // ****************************************************
+ // JCA adapter methods
+ // ****************************************************
+
+ /**
+ * Initialize this cipher object with a proper key and some random seed.
+ * Before a cipher object is ready for data processing, it has to be
+ * initialized according to the desired cryptographic operation, which is
+ * specified by the <tt>opMode</tt> parameter.
+ * <p/>
+ * If this cipher (including its underlying mode or padding scheme) requires
+ * any random bytes, it will obtain them from <tt>random</tt>.
+ * <p/>
+ * Note: If the mode needs an initialization vector, a blank array is used
+ * in this case.
+ *
+ * @param opMode the operation mode ({@link #ENCRYPT_MODE} or
+ * {@link #DECRYPT_MODE})
+ * @param key the key
+ * @param random the random seed
+ * @throws java.security.InvalidKeyException if the key is inappropriate for initializing this cipher.
+ */
+ protected final void engineInit(int opMode, java.security.Key key,
+ java.security.SecureRandom random)
+ throws java.security.InvalidKeyException
+ {
+
+ try
+ {
+ engineInit(opMode, key,
+ (java.security.spec.AlgorithmParameterSpec)null, random);
+ }
+ catch (java.security.InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException(e.getMessage());
+ }
+ }
+
+ /**
+ * Initialize this cipher with a key, a set of algorithm parameters, and a
+ * source of randomness. The cipher is initialized for encryption or
+ * decryption, depending on the value of <tt>opMode</tt>.
+ * <p/>
+ * If this cipher (including its underlying mode or padding scheme) requires
+ * any random bytes, it will obtain them from <tt>random</tt>. Note that
+ * when a {@link BlockCipher} object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it.
+ * <p/>
+ * Note: If the mode needs an initialization vector, a try to retrieve it
+ * from the AlgorithmParametersSpec is made.
+ *
+ * @param opMode the operation mode ({@link #ENCRYPT_MODE} or
+ * {@link #DECRYPT_MODE})
+ * @param key the key
+ * @param algParams the algorithm parameters
+ * @param random the random seed
+ * @throws java.security.InvalidKeyException if the key is inappropriate for initializing this block
+ * cipher.
+ * @throws java.security.InvalidAlgorithmParameterException if the parameters are inappropriate for initializing this
+ * block cipher.
+ */
+ protected final void engineInit(int opMode, java.security.Key key,
+ java.security.AlgorithmParameters algParams,
+ java.security.SecureRandom random)
+ throws java.security.InvalidKeyException,
+ java.security.InvalidAlgorithmParameterException
+ {
+
+ // if algParams are not specified, initialize without them
+ if (algParams == null)
+ {
+ engineInit(opMode, key, random);
+ return;
+ }
+
+ AlgorithmParameterSpec paramSpec = null;
+ // XXX getting AlgorithmParameterSpec from AlgorithmParameters
+
+ engineInit(opMode, key, paramSpec, random);
+ }
+
+ /**
+ * Initialize this cipher with a key, a set of algorithm parameters, and a
+ * source of randomness. The cipher is initialized for one of the following
+ * four operations: encryption, decryption, key wrapping or key unwrapping,
+ * depending on the value of opMode. If this cipher (including its
+ * underlying feedback or padding scheme) requires any random bytes (e.g.,
+ * for parameter generation), it will get them from random. Note that when a
+ * Cipher object is initialized, it loses all previously-acquired state. In
+ * other words, initializing a Cipher is equivalent to creating a new
+ * instance of that Cipher and initializing it.
+ *
+ * @param opMode the operation mode ({@link #ENCRYPT_MODE} or
+ * {@link #DECRYPT_MODE})
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ * @param javaRand the source of randomness
+ * @throws java.security.InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws java.security.InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is being initialized for
+ * decryption and requires algorithm parameters and the
+ * parameters are null.
+ */
+ protected void engineInit(int opMode, java.security.Key key,
+ java.security.spec.AlgorithmParameterSpec params,
+ java.security.SecureRandom javaRand)
+ throws java.security.InvalidKeyException,
+ java.security.InvalidAlgorithmParameterException
+ {
+
+ if ((params != null) && !(params instanceof AlgorithmParameterSpec))
+ {
+ throw new java.security.InvalidAlgorithmParameterException();
+ }
+
+ if ((key == null) || !(key instanceof Key))
+ {
+ throw new java.security.InvalidKeyException();
+ }
+
+ this.opMode = opMode;
+
+ if (opMode == ENCRYPT_MODE)
+ {
+ SecureRandom flexiRand = javaRand;
+ initEncrypt((Key)key, (AlgorithmParameterSpec)params, flexiRand);
+
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+ initDecrypt((Key)key, (AlgorithmParameterSpec)params);
+
+ }
+ }
+
+ /**
+ * Return the result of the last step of a multi-step en-/decryption
+ * operation or the result of a single-step en-/decryption operation by
+ * processing the given input data and any remaining buffered data. The data
+ * to be processed is given in an input byte array. Beginning at
+ * inputOffset, only the first inputLen bytes are en-/decrypted, including
+ * any buffered bytes of a previous update operation. If necessary, padding
+ * is performed. The result is returned as a output byte array.
+ *
+ * @param input the byte array holding the data to be processed
+ * @param inOff the offset indicating the start position within the input
+ * byte array
+ * @param inLen the number of bytes to be processed
+ * @return the byte array containing the en-/decrypted data
+ * @throws javax.crypto.IllegalBlockSizeException if the ciphertext length is not a multiple of the
+ * blocklength.
+ * @throws javax.crypto.BadPaddingException if unpadding is not possible.
+ */
+ protected final byte[] engineDoFinal(byte[] input, int inOff, int inLen)
+ throws javax.crypto.IllegalBlockSizeException,
+ javax.crypto.BadPaddingException
+ {
+ return doFinal(input, inOff, inLen);
+ }
+
+ /**
+ * Perform the last step of a multi-step en-/decryption operation or a
+ * single-step en-/decryption operation by processing the given input data
+ * and any remaining buffered data. The data to be processed is given in an
+ * input byte array. Beginning at inputOffset, only the first inputLen bytes
+ * are en-/decrypted, including any buffered bytes of a previous update
+ * operation. If necessary, padding is performed. The result is stored in
+ * the given output byte array, beginning at outputOffset. The number of
+ * bytes stored in this byte array are returned.
+ *
+ * @param input the byte array holding the data to be processed
+ * @param inOff the offset indicating the start position within the input
+ * byte array
+ * @param inLen the number of bytes to be processed
+ * @param output the byte array for holding the result
+ * @param outOff the offset indicating the start position within the output
+ * byte array to which the en/decrypted data is written
+ * @return the number of bytes stored in the output byte array
+ * @throws javax.crypto.ShortBufferException if the output buffer is too short to hold the output.
+ * @throws javax.crypto.IllegalBlockSizeException if the ciphertext length is not a multiple of the
+ * blocklength.
+ * @throws javax.crypto.BadPaddingException if unpadding is not possible.
+ */
+ protected final int engineDoFinal(byte[] input, int inOff, int inLen,
+ byte[] output, int outOff)
+ throws javax.crypto.ShortBufferException,
+ javax.crypto.IllegalBlockSizeException,
+ javax.crypto.BadPaddingException
+ {
+ return doFinal(input, inOff, inLen, output, outOff);
+ }
+
+ /**
+ * @return the block size (in bytes), or 0 if the underlying algorithm is
+ * not a block cipher
+ */
+ protected final int engineGetBlockSize()
+ {
+ return getBlockSize();
+ }
+
+ /**
+ * Return the key size of the given key object in bits.
+ *
+ * @param key the key object
+ * @return the key size in bits of the given key object
+ * @throws java.security.InvalidKeyException if key is invalid.
+ */
+ protected final int engineGetKeySize(java.security.Key key)
+ throws java.security.InvalidKeyException
+ {
+ if (!(key instanceof Key))
+ {
+ throw new java.security.InvalidKeyException("Unsupported key.");
+ }
+ return getKeySize((Key)key);
+ }
+
+ /**
+ * Return the initialization vector. This is useful in the context of
+ * password-based encryption or decryption, where the IV is derived from a
+ * user-provided passphrase.
+ *
+ * @return the initialization vector in a new buffer, or <tt>null</tt> if
+ * the underlying algorithm does not use an IV, or if the IV has not
+ * yet been set.
+ */
+ protected final byte[] engineGetIV()
+ {
+ return getIV();
+ }
+
+ /**
+ * Return the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next update or doFinal operation, given
+ * the input length inputLen (in bytes).
+ * <p/>
+ * This call takes into account any unprocessed (buffered) data from a
+ * previous update call, and padding.
+ * <p/>
+ * The actual output length of the next update or doFinal call may be
+ * smaller than the length returned by this method.
+ *
+ * @param inLen the input length (in bytes)
+ * @return the required output buffer size (in bytes)
+ */
+ protected final int engineGetOutputSize(int inLen)
+ {
+ return getOutputSize(inLen);
+ }
+
+ /**
+ * Returns the parameters used with this cipher.
+ * <p/>
+ * The returned parameters may be the same that were used to initialize this
+ * cipher, or may contain the default set of parameters or a set of randomly
+ * generated parameters used by the underlying cipher implementation
+ * (provided that the underlying cipher implementation uses a default set of
+ * parameters or creates new parameters if it needs parameters but was not
+ * initialized with any).
+ *
+ * @return the parameters used with this cipher, or null if this cipher does
+ * not use any parameters.
+ */
+ protected final java.security.AlgorithmParameters engineGetParameters()
+ {
+ // TODO
+ return null;
+ }
+
+ /**
+ * Set the mode of this cipher.
+ *
+ * @param modeName the cipher mode
+ * @throws java.security.NoSuchAlgorithmException if neither the mode with the given name nor the default
+ * mode can be found
+ */
+ protected final void engineSetMode(String modeName)
+ throws java.security.NoSuchAlgorithmException
+ {
+ setMode(modeName);
+ }
+
+ /**
+ * Set the padding scheme of this cipher.
+ *
+ * @param paddingName the padding scheme
+ * @throws javax.crypto.NoSuchPaddingException if the requested padding scheme cannot be found.
+ */
+ protected final void engineSetPadding(String paddingName)
+ throws javax.crypto.NoSuchPaddingException
+ {
+ setPadding(paddingName);
+ }
+
+ /**
+ * Return the result of the next step of a multi-step en-/decryption
+ * operation. The data to be processed is given in an input byte array.
+ * Beginning at inputOffset, only the first inputLen bytes are
+ * en-/decrypted. The result is returned as a byte array.
+ *
+ * @param input the byte array holding the data to be processed
+ * @param inOff the offset indicating the start position within the input
+ * byte array
+ * @param inLen the number of bytes to be processed
+ * @return the byte array containing the en-/decrypted data
+ */
+ protected final byte[] engineUpdate(byte[] input, int inOff, int inLen)
+ {
+ return update(input, inOff, inLen);
+ }
+
+ /**
+ * Perform the next step of a multi-step en-/decryption operation. The data
+ * to be processed is given in an input byte array. Beginning at
+ * inputOffset, only the first inputLen bytes are en-/decrypted. The result
+ * is stored in the given output byte array, beginning at outputOffset. The
+ * number of bytes stored in this output byte array are returned.
+ *
+ * @param input the byte array holding the data to be processed
+ * @param inOff the offset indicating the start position within the input
+ * byte array
+ * @param inLen the number of bytes to be processed
+ * @param output the byte array for holding the result
+ * @param outOff the offset indicating the start position within the output
+ * byte array to which the en-/decrypted data is written
+ * @return the number of bytes that are stored in the output byte array
+ * @throws javax.crypto.ShortBufferException if the output buffer is too short to hold the output.
+ */
+ protected final int engineUpdate(final byte[] input, final int inOff,
+ final int inLen, byte[] output, final int outOff)
+ throws javax.crypto.ShortBufferException
+ {
+ return update(input, inOff, inLen, output, outOff);
+ }
+
+ /**
+ * Initialize this cipher with a key, a set of algorithm parameters, and a
+ * source of randomness for encryption.
+ * <p/>
+ * If this cipher requires any algorithm parameters and paramSpec is null,
+ * the underlying cipher implementation is supposed to generate the required
+ * parameters itself (using provider-specific default or random values) if
+ * it is being initialized for encryption, and raise an
+ * InvalidAlgorithmParameterException if it is being initialized for
+ * decryption. The generated parameters can be retrieved using
+ * engineGetParameters or engineGetIV (if the parameter is an IV).
+ * <p/>
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ * <p/>
+ * Note that when a {@link BlockCipher} object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it.
+ *
+ * @param key the encryption key
+ * @param cipherParams the cipher parameters
+ * @param random the source of randomness
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * block cipher.
+ * @throws InvalidAlgorithmParameterException if the parameters are inappropriate for initializing this
+ * block cipher.
+ */
+ public abstract void initEncrypt(Key key,
+ AlgorithmParameterSpec cipherParams, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Initialize this cipher with a key, a set of algorithm parameters, and a
+ * source of randomness for decryption.
+ * <p/>
+ * If this cipher requires any algorithm parameters and paramSpec is null,
+ * the underlying cipher implementation is supposed to generate the required
+ * parameters itself (using provider-specific default or random values) if
+ * it is being initialized for encryption, and throw an
+ * {@link InvalidAlgorithmParameterException} if it is being initialized for
+ * decryption. The generated parameters can be retrieved using
+ * engineGetParameters or engineGetIV (if the parameter is an IV).
+ * <p/>
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ * <p/>
+ * Note that when a {@link BlockCipher} object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it.
+ *
+ * @param key the encryption key
+ * @param cipherParams the cipher parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * block cipher.
+ * @throws InvalidAlgorithmParameterException if the parameters are inappropriate for initializing this
+ * block cipher.
+ */
+ public abstract void initDecrypt(Key key,
+ AlgorithmParameterSpec cipherParams)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException;
+
+ /**
+ * @return the name of this cipher
+ */
+ public abstract String getName();
+
+ /**
+ * @return the block size (in bytes), or 0 if the underlying algorithm is
+ * not a block cipher
+ */
+ public abstract int getBlockSize();
+
+ /**
+ * Returns the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next update or doFinal operation, given
+ * the input length inputLen (in bytes).
+ * <p/>
+ * This call takes into account any unprocessed (buffered) data from a
+ * previous update call, and padding.
+ * <p/>
+ * The actual output length of the next update or doFinal call may be
+ * smaller than the length returned by this method.
+ *
+ * @param inputLen the input length (in bytes)
+ * @return the required output buffer size (in bytes)
+ */
+ public abstract int getOutputSize(int inputLen);
+
+ /**
+ * Return the key size of the given key object in bits.
+ *
+ * @param key the key object
+ * @return the key size in bits of the given key object
+ * @throws InvalidKeyException if key is invalid.
+ */
+ public abstract int getKeySize(Key key)
+ throws InvalidKeyException;
+
+ /**
+ * Returns the parameters used with this cipher.
+ * <p/>
+ * The returned parameters may be the same that were used to initialize this
+ * cipher, or may contain the default set of parameters or a set of randomly
+ * generated parameters used by the underlying cipher implementation
+ * (provided that the underlying cipher implementation uses a default set of
+ * parameters or creates new parameters if it needs parameters but was not
+ * initialized with any).
+ *
+ * @return the parameters used with this cipher, or null if this cipher does
+ * not use any parameters.
+ */
+ public abstract AlgorithmParameterSpec getParameters();
+
+ /**
+ * Return the initialization vector. This is useful in the context of
+ * password-based encryption or decryption, where the IV is derived from a
+ * user-provided passphrase.
+ *
+ * @return the initialization vector in a new buffer, or <tt>null</tt> if
+ * the underlying algorithm does not use an IV, or if the IV has not
+ * yet been set.
+ */
+ public abstract byte[] getIV();
+
+ /**
+ * Set the mode of this cipher.
+ *
+ * @param mode the cipher mode
+ * @throws NoSuchModeException if the requested mode cannot be found.
+ */
+ protected abstract void setMode(String mode)
+ throws NoSuchAlgorithmException;
+
+ /**
+ * Set the padding mechanism of this cipher.
+ *
+ * @param padding the padding mechanism
+ * @throws NoSuchPaddingException if the requested padding scheme cannot be found.
+ */
+ protected abstract void setPadding(String padding)
+ throws NoSuchPaddingException;
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @return a new buffer with the result (maybe an empty byte array)
+ */
+ public final byte[] update(byte[] input)
+ {
+ return update(input, 0, input.length);
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result (maybe an empty byte array)
+ */
+ public abstract byte[] update(byte[] input, int inOff, int inLen);
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the output buffer
+ * @param outOff the offset where the result is stored
+ * @return the length of the output
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ */
+ public abstract int update(byte[] input, int inOff, int inLen,
+ byte[] output, int outOff)
+ throws ShortBufferException;
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @return a new buffer with the result
+ * @throws IllegalBlockSizeException if this cipher is a block cipher and the total input
+ * length is not a multiple of the block size (for
+ * encryption when no padding is used or for decryption).
+ * @throws BadPaddingException if this cipher is a block cipher and unpadding fails.
+ */
+ public final byte[] doFinal()
+ throws IllegalBlockSizeException,
+ BadPaddingException
+ {
+ return doFinal(null, 0, 0);
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @return a new buffer with the result
+ * @throws IllegalBlockSizeException if this cipher is a block cipher and the total input
+ * length is not a multiple of the block size (for
+ * encryption when no padding is used or for decryption).
+ * @throws BadPaddingException if this cipher is a block cipher and unpadding fails.
+ */
+ public final byte[] doFinal(byte[] input)
+ throws IllegalBlockSizeException,
+ BadPaddingException
+ {
+ return doFinal(input, 0, input.length);
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result
+ * @throws IllegalBlockSizeException if this cipher is a block cipher and the total input
+ * length is not a multiple of the block size (for
+ * encryption when no padding is used or for decryption).
+ * @throws BadPaddingException if this cipher is a block cipher and unpadding fails.
+ */
+ public abstract byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws IllegalBlockSizeException, BadPaddingException;
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the buffer for the result
+ * @param outOff the offset where the result is stored
+ * @return the output length
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ * @throws IllegalBlockSizeException if this cipher is a block cipher and the total input
+ * length is not a multiple of the block size (for
+ * encryption when no padding is used or for decryption).
+ * @throws BadPaddingException if this cipher is a block cipher and unpadding fails.
+ */
+ public abstract int doFinal(byte[] input, int inOff, int inLen,
+ byte[] output, int outOff)
+ throws ShortBufferException,
+ IllegalBlockSizeException, BadPaddingException;
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/KeyUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/KeyUtil.java
new file mode 100644
index 000000000..ae780b6d2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/KeyUtil.java
@@ -0,0 +1,72 @@
+package org.spongycastle.pqc.jcajce.provider.util;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public class KeyUtil
+{
+ public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, ASN1Encodable keyData)
+ {
+ try
+ {
+ return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, byte[] keyData)
+ {
+ try
+ {
+ return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedSubjectPublicKeyInfo(SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedPrivateKeyInfo(AlgorithmIdentifier algId, ASN1Encodable privKey)
+ {
+ try
+ {
+ PrivateKeyInfo info = new PrivateKeyInfo(algId, privKey.toASN1Primitive());
+
+ return getEncodedPrivateKeyInfo(info);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedPrivateKeyInfo(PrivateKeyInfo info)
+ {
+ try
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/ECCKeyGenParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/ECCKeyGenParameterSpec.java
new file mode 100644
index 000000000..ad4b451b8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/ECCKeyGenParameterSpec.java
@@ -0,0 +1,192 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+import java.security.InvalidParameterException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.pqc.math.linearalgebra.PolynomialRingGF2;
+
+/**
+ * This class provides a specification for the parameters that are used by the
+ * McEliece, McElieceCCA2, and Niederreiter key pair generators.
+ *
+ * @see org.spongycastle.pqc.ecc.mceliece.McElieceKeyPairGenerator
+ * @see org.spongycastle.pqc.ecc.mceliece.McElieceCCA2KeyPairGenerator
+ * @see org.spongycastle.pqc.ecc.niederreiter.NiederreiterKeyPairGenerator
+ */
+public class ECCKeyGenParameterSpec
+ implements AlgorithmParameterSpec
+{
+
+ /**
+ * The default extension degree
+ */
+ public static final int DEFAULT_M = 11;
+
+ /**
+ * The default error correcting capability.
+ */
+ public static final int DEFAULT_T = 50;
+
+ /**
+ * extension degree of the finite field GF(2^m)
+ */
+ private int m;
+
+ /**
+ * error correction capability of the code
+ */
+ private int t;
+
+ /**
+ * length of the code
+ */
+ private int n;
+
+ /**
+ * the field polynomial
+ */
+ private int fieldPoly;
+
+ /**
+ * Constructor. Set the default parameters: extension degree.
+ */
+ public ECCKeyGenParameterSpec()
+ {
+ this(DEFAULT_M, DEFAULT_T);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param keysize the length of a Goppa code
+ * @throws InvalidParameterException if <tt>keysize &lt; 1</tt>.
+ */
+ public ECCKeyGenParameterSpec(int keysize)
+ throws InvalidParameterException
+ {
+ if (keysize < 1)
+ {
+ throw new InvalidParameterException("key size must be positive");
+ }
+ m = 0;
+ n = 1;
+ while (n < keysize)
+ {
+ n <<= 1;
+ m++;
+ }
+ t = n >>> 1;
+ t /= m;
+ fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @throws InvalidParameterException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt>.
+ */
+ public ECCKeyGenParameterSpec(int m, int t)
+ throws InvalidParameterException
+ {
+ if (m < 1)
+ {
+ throw new InvalidParameterException("m must be positive");
+ }
+ if (m > 32)
+ {
+ throw new InvalidParameterException("m is too large");
+ }
+ this.m = m;
+ n = 1 << m;
+ if (t < 0)
+ {
+ throw new InvalidParameterException("t must be positive");
+ }
+ if (t > n)
+ {
+ throw new InvalidParameterException("t must be less than n = 2^m");
+ }
+ this.t = t;
+ fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param m degree of the finite field GF(2^m)
+ * @param t error correction capability of the code
+ * @param poly the field polynomial
+ * @throws InvalidParameterException if <tt>m &lt; 1</tt> or <tt>m &gt; 32</tt> or
+ * <tt>t &lt; 0</tt> or <tt>t &gt; n</tt> or
+ * <tt>poly</tt> is not an irreducible field polynomial.
+ */
+ public ECCKeyGenParameterSpec(int m, int t, int poly)
+ throws InvalidParameterException
+ {
+ this.m = m;
+ if (m < 1)
+ {
+ throw new InvalidParameterException("m must be positive");
+ }
+ if (m > 32)
+ {
+ throw new InvalidParameterException(" m is too large");
+ }
+ this.n = 1 << m;
+ this.t = t;
+ if (t < 0)
+ {
+ throw new InvalidParameterException("t must be positive");
+ }
+ if (t > n)
+ {
+ throw new InvalidParameterException("t must be less than n = 2^m");
+ }
+ if ((PolynomialRingGF2.degree(poly) == m)
+ && (PolynomialRingGF2.isIrreducible(poly)))
+ {
+ this.fieldPoly = poly;
+ }
+ else
+ {
+ throw new InvalidParameterException(
+ "polynomial is not a field polynomial for GF(2^m)");
+ }
+ }
+
+ /**
+ * @return the extension degree of the finite field GF(2^m)
+ */
+ public int getM()
+ {
+ return m;
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the field polynomial
+ */
+ public int getFieldPoly()
+ {
+ return fieldPoly;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSKeySpec.java
new file mode 100644
index 000000000..5af141022
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSKeySpec.java
@@ -0,0 +1,29 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+import java.security.spec.KeySpec;
+
+import org.spongycastle.pqc.crypto.gmss.GMSSParameters;
+
+public class GMSSKeySpec
+ implements KeySpec
+{
+ /**
+ * The GMSSParameterSet
+ */
+ private GMSSParameters gmssParameterSet;
+
+ protected GMSSKeySpec(GMSSParameters gmssParameterSet)
+ {
+ this.gmssParameterSet = gmssParameterSet;
+ }
+
+ /**
+ * Returns the GMSS parameter set
+ *
+ * @return The GMSS parameter set
+ */
+ public GMSSParameters getParameters()
+ {
+ return gmssParameterSet;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSPrivateKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSPrivateKeySpec.java
new file mode 100644
index 000000000..e61aca4c6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSPrivateKeySpec.java
@@ -0,0 +1,353 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+import java.security.spec.KeySpec;
+import java.util.Vector;
+
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.pqc.crypto.gmss.GMSSLeaf;
+import org.spongycastle.pqc.crypto.gmss.GMSSParameters;
+import org.spongycastle.pqc.crypto.gmss.GMSSRootCalc;
+import org.spongycastle.pqc.crypto.gmss.GMSSRootSig;
+import org.spongycastle.pqc.crypto.gmss.Treehash;
+import org.spongycastle.util.Arrays;
+
+
+/**
+ * This class provides a specification for a GMSS private key.
+ */
+public class GMSSPrivateKeySpec
+ implements KeySpec
+{
+
+ private int[] index;
+
+ private byte[][] currentSeed;
+ private byte[][] nextNextSeed;
+
+ private byte[][][] currentAuthPath;
+ private byte[][][] nextAuthPath;
+
+ private Treehash[][] currentTreehash;
+ private Treehash[][] nextTreehash;
+
+ private Vector[] currentStack;
+ private Vector[] nextStack;
+
+ private Vector[][] currentRetain;
+ private Vector[][] nextRetain;
+
+ private byte[][][] keep;
+
+ private GMSSLeaf[] nextNextLeaf;
+ private GMSSLeaf[] upperLeaf;
+ private GMSSLeaf[] upperTreehashLeaf;
+
+ private int[] minTreehash;
+
+ private GMSSParameters gmssPS;
+
+ private byte[][] nextRoot;
+ private GMSSRootCalc[] nextNextRoot;
+
+ private byte[][] currentRootSig;
+ private GMSSRootSig[] nextRootSig;
+
+ /**
+ * @param index tree indices
+ * @param currentSeed seed for the generation of private OTS keys for the
+ * current subtrees (TREE)
+ * @param nextNextSeed seed for the generation of private OTS keys for the
+ * subtrees after next (TREE++)
+ * @param currentAuthPath array of current authentication paths (AUTHPATH)
+ * @param nextAuthPath array of next authentication paths (AUTHPATH+)
+ * @param keep keep array for the authPath algorithm
+ * @param currentTreehash treehash for authPath algorithm of current tree
+ * @param nextTreehash treehash for authPath algorithm of next tree (TREE+)
+ * @param currentStack shared stack for authPath algorithm of current tree
+ * @param nextStack shared stack for authPath algorithm of next tree (TREE+)
+ * @param currentRetain retain stack for authPath algorithm of current tree
+ * @param nextRetain retain stack for authPath algorithm of next tree (TREE+)
+ * @param nextNextLeaf array of upcoming leafs of the tree after next (LEAF++) of
+ * each layer
+ * @param upperLeaf needed for precomputation of upper nodes
+ * @param upperTreehashLeaf needed for precomputation of upper treehash nodes
+ * @param minTreehash index of next treehash instance to receive an update
+ * @param nextRoot the roots of the next trees (ROOT+)
+ * @param nextNextRoot the roots of the tree after next (ROOT++)
+ * @param currentRootSig array of signatures of the roots of the current subtrees
+ * (SIG)
+ * @param nextRootSig array of signatures of the roots of the next subtree
+ * (SIG+)
+ * @param gmssParameterset the GMSS Parameterset
+ */
+ public GMSSPrivateKeySpec(int[] index, byte[][] currentSeed,
+ byte[][] nextNextSeed, byte[][][] currentAuthPath,
+ byte[][][] nextAuthPath, Treehash[][] currentTreehash,
+ Treehash[][] nextTreehash, Vector[] currentStack,
+ Vector[] nextStack, Vector[][] currentRetain,
+ Vector[][] nextRetain, byte[][][] keep, GMSSLeaf[] nextNextLeaf,
+ GMSSLeaf[] upperLeaf, GMSSLeaf[] upperTreehashLeaf,
+ int[] minTreehash, byte[][] nextRoot, GMSSRootCalc[] nextNextRoot,
+ byte[][] currentRootSig, GMSSRootSig[] nextRootSig,
+ GMSSParameters gmssParameterset)
+ {
+ this.index = index;
+ this.currentSeed = currentSeed;
+ this.nextNextSeed = nextNextSeed;
+ this.currentAuthPath = currentAuthPath;
+ this.nextAuthPath = nextAuthPath;
+ this.currentTreehash = currentTreehash;
+ this.nextTreehash = nextTreehash;
+ this.currentStack = currentStack;
+ this.nextStack = nextStack;
+ this.currentRetain = currentRetain;
+ this.nextRetain = nextRetain;
+ this.keep = keep;
+ this.nextNextLeaf = nextNextLeaf;
+ this.upperLeaf = upperLeaf;
+ this.upperTreehashLeaf = upperTreehashLeaf;
+ this.minTreehash = minTreehash;
+ this.nextRoot = nextRoot;
+ this.nextNextRoot = nextNextRoot;
+ this.currentRootSig = currentRootSig;
+ this.nextRootSig = nextRootSig;
+ this.gmssPS = gmssParameterset;
+ }
+
+ public int[] getIndex()
+ {
+ return Arrays.clone(index);
+ }
+
+ public byte[][] getCurrentSeed()
+ {
+ return clone(currentSeed);
+ }
+
+ public byte[][] getNextNextSeed()
+ {
+ return clone(nextNextSeed);
+ }
+
+ public byte[][][] getCurrentAuthPath()
+ {
+ return clone(currentAuthPath);
+ }
+
+ public byte[][][] getNextAuthPath()
+ {
+ return clone(nextAuthPath);
+ }
+
+ public Treehash[][] getCurrentTreehash()
+ {
+ return clone(currentTreehash);
+ }
+
+ public Treehash[][] getNextTreehash()
+ {
+ return clone(nextTreehash);
+ }
+
+ public byte[][][] getKeep()
+ {
+ return clone(keep);
+ }
+
+ public Vector[] getCurrentStack()
+ {
+ return clone(currentStack);
+ }
+
+ public Vector[] getNextStack()
+ {
+ return clone(nextStack);
+ }
+
+ public Vector[][] getCurrentRetain()
+ {
+ return clone(currentRetain);
+ }
+
+ public Vector[][] getNextRetain()
+ {
+ return clone(nextRetain);
+ }
+
+ public GMSSLeaf[] getNextNextLeaf()
+ {
+ return clone(nextNextLeaf);
+ }
+
+ public GMSSLeaf[] getUpperLeaf()
+ {
+ return clone(upperLeaf);
+ }
+
+ public GMSSLeaf[] getUpperTreehashLeaf()
+ {
+ return clone(upperTreehashLeaf);
+ }
+
+ public int[] getMinTreehash()
+ {
+ return Arrays.clone(minTreehash);
+ }
+
+ public GMSSRootSig[] getNextRootSig()
+ {
+ return clone(nextRootSig);
+ }
+
+ public GMSSParameters getGmssPS()
+ {
+ return gmssPS;
+ }
+
+ public byte[][] getNextRoot()
+ {
+ return clone(nextRoot);
+ }
+
+ public GMSSRootCalc[] getNextNextRoot()
+ {
+ return clone(nextNextRoot);
+ }
+
+ public byte[][] getCurrentRootSig()
+ {
+ return clone(currentRootSig);
+ }
+
+ private static GMSSLeaf[] clone(GMSSLeaf[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ GMSSLeaf[] copy = new GMSSLeaf[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ private static GMSSRootCalc[] clone(GMSSRootCalc[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ GMSSRootCalc[] copy = new GMSSRootCalc[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ private static GMSSRootSig[] clone(GMSSRootSig[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ GMSSRootSig[] copy = new GMSSRootSig[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ private static byte[][] clone(byte[][] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ byte[][] copy = new byte[data.length][];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = Arrays.clone(data[i]);
+ }
+
+ return copy;
+ }
+
+ private static byte[][][] clone(byte[][][] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ byte[][][] copy = new byte[data.length][][];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = clone(data[i]);
+ }
+
+ return copy;
+ }
+
+ private static Treehash[] clone(Treehash[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ Treehash[] copy = new Treehash[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ private static Treehash[][] clone(Treehash[][] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ Treehash[][] copy = new Treehash[data.length][];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = clone(data[i]);
+ }
+
+ return copy;
+ }
+
+ private static Vector[] clone(Vector[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ Vector[] copy = new Vector[data.length];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = new Vector(data[i]);
+ }
+
+ return copy;
+ }
+
+ private static Vector[][] clone(Vector[][] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ Vector[][] copy = new Vector[data.length][];
+
+ for (int i = 0; i != data.length; i++)
+ {
+ copy[i] = clone(data[i]);
+ }
+
+ return copy;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSPublicKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSPublicKeySpec.java
new file mode 100644
index 000000000..3da9c97c3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/GMSSPublicKeySpec.java
@@ -0,0 +1,40 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+import org.spongycastle.pqc.crypto.gmss.GMSSParameters;
+
+/**
+ * This class provides a specification for a GMSS public key.
+ *
+ * @see org.spongycastle.pqc.jcajce.provider.gmss.BCGMSSPublicKey
+ */
+public class GMSSPublicKeySpec
+ extends GMSSKeySpec
+{
+ /**
+ * The GMSS public key
+ */
+ private byte[] gmssPublicKey;
+
+ /**
+ * The constructor.
+ *
+ * @param key a raw GMSS public key
+ * @param gmssParameterSet an instance of GMSSParameterSet
+ */
+ public GMSSPublicKeySpec(byte[] key, GMSSParameters gmssParameterSet)
+ {
+ super(gmssParameterSet);
+
+ this.gmssPublicKey = key;
+ }
+
+ /**
+ * Returns the GMSS public key
+ *
+ * @return The GMSS public key
+ */
+ public byte[] getPublicKey()
+ {
+ return gmssPublicKey;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2ParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2ParameterSpec.java
new file mode 100644
index 000000000..76dd8e0fe
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2ParameterSpec.java
@@ -0,0 +1,63 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class provides a specification for the parameters of the CCA2-secure
+ * variants of the McEliece PKCS that are used with
+ * {@link McElieceFujisakiCipher}, {@link McElieceKobaraImaiCipher}, and
+ * {@link McEliecePointchevalCipher}.
+ *
+ * @see McElieceFujisakiCipher
+ * @see McElieceKobaraImaiCipher
+ * @see McEliecePointchevalCipher
+ */
+public class McElieceCCA2ParameterSpec
+ implements AlgorithmParameterSpec
+{
+
+ /**
+ * The default message digest ("SHA256").
+ */
+ public static final String DEFAULT_MD = "SHA256";
+
+ private String mdName;
+
+ /**
+ * Construct the default parameters. Choose the
+ */
+ public McElieceCCA2ParameterSpec()
+ {
+ this(DEFAULT_MD);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param mdName the name of the hash function
+ */
+ public McElieceCCA2ParameterSpec(String mdName)
+ {
+ // check whether message digest is available
+ // TODO: this method not used!
+// try {
+// Registry.getMessageDigest(mdName);
+// } catch (NoSuchAlgorithmException nsae) {
+// throw new InvalidParameterException("Message digest '" + mdName
+// + "' not found'.");
+// }
+
+ // assign message digest name
+ this.mdName = mdName;
+ }
+
+ /**
+ * @return the name of the hash function
+ */
+ public String getMDName()
+ {
+ return mdName;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2PrivateKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2PrivateKeySpec.java
new file mode 100644
index 000000000..c13f8341e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2PrivateKeySpec.java
@@ -0,0 +1,161 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+import java.security.spec.KeySpec;
+
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.spongycastle.pqc.math.linearalgebra.GF2mField;
+import org.spongycastle.pqc.math.linearalgebra.Permutation;
+import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+/**
+ * This class provides a specification for a McEliece CCA2 private key.
+ *
+ * @see JDKMcElieceCCA2PrivateKey
+ */
+public class McElieceCCA2PrivateKeySpec
+ implements KeySpec
+{
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the dimension of the code
+ private int k;
+
+ // the finte field GF(2^m)
+ private GF2mField field;
+
+ // the irreducible Goppa polynomial
+ private PolynomialGF2mSmallM goppaPoly;
+
+ // the permutation
+ private Permutation p;
+
+ // the canonical check matrix
+ private GF2Matrix h;
+
+ // the matrix used to compute square roots in (GF(2^m))^t
+ private PolynomialGF2mSmallM[] qInv;
+
+ /**
+ * Constructor.
+ *
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param field the finite field <tt>GF(2<sup>m</sup>)</tt>
+ * @param gp the irreducible Goppa polynomial
+ * @param p the permutation
+ * @param h the canonical check matrix
+ * @param qInv the matrix used to compute square roots in
+ * <tt>(GF(2^m))^t</tt>
+ */
+ public McElieceCCA2PrivateKeySpec(String oid, int n, int k, GF2mField field,
+ PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h,
+ PolynomialGF2mSmallM[] qInv)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ this.field = field;
+ this.goppaPoly = gp;
+ this.p = p;
+ this.h = h;
+ this.qInv = qInv;
+ }
+
+ /**
+ * Constructor used by the {@link McElieceKeyFactory}.
+ *
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param encFieldPoly the encoded field polynomial defining the finite field
+ * <tt>GF(2<sup>m</sup>)</tt>
+ * @param encGoppaPoly the encoded irreducible Goppa polynomial
+ * @param encP the encoded permutation
+ * @param encH the encoded canonical check matrix
+ * @param encQInv the encoded matrix used to compute square roots in
+ * <tt>(GF(2^m))^t</tt>
+ */
+ public McElieceCCA2PrivateKeySpec(String oid, int n, int k, byte[] encFieldPoly,
+ byte[] encGoppaPoly, byte[] encP, byte[] encH, byte[][] encQInv)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ field = new GF2mField(encFieldPoly);
+ goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly);
+ p = new Permutation(encP);
+ h = new GF2Matrix(encH);
+ qInv = new PolynomialGF2mSmallM[encQInv.length];
+ for (int i = 0; i < encQInv.length; i++)
+ {
+ qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]);
+ }
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return k;
+ }
+
+ /**
+ * @return the finite field
+ */
+ public GF2mField getField()
+ {
+ return field;
+ }
+
+ /**
+ * @return the irreducible Goppa polynomial
+ */
+ public PolynomialGF2mSmallM getGoppaPoly()
+ {
+ return goppaPoly;
+ }
+
+ /**
+ * @return the permutation P
+ */
+ public Permutation getP()
+ {
+ return p;
+ }
+
+ /**
+ * @return the canonical check matrix H
+ */
+ public GF2Matrix getH()
+ {
+ return h;
+ }
+
+ /**
+ * @return the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
+ */
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ return qInv;
+ }
+
+ public String getOIDString()
+ {
+ return oid;
+
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2PublicKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2PublicKeySpec.java
new file mode 100644
index 000000000..d5eb49cab
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McElieceCCA2PublicKeySpec.java
@@ -0,0 +1,88 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+import java.security.spec.KeySpec;
+
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+
+
+/**
+ * This class provides a specification for a McEliece CCA2 public key.
+ *
+ * @see org.spongycastle.pqc.jcajce.provider.mceliece.BCMcElieceCCA2PublicKey
+ */
+public class McElieceCCA2PublicKeySpec
+ implements KeySpec
+{
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the error correction capability of the code
+ private int t;
+
+ // the generator matrix
+ private GF2Matrix matrixG;
+
+ /**
+ * Constructor.
+ *
+ * @param n length of the code
+ * @param t error correction capability
+ * @param matrix generator matrix
+ */
+ public McElieceCCA2PublicKeySpec(String oid, int n, int t, GF2Matrix matrix)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.matrixG = new GF2Matrix(matrix);
+ }
+
+ /**
+ * Constructor (used by {@link org.spongycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi}).
+ *
+ * @param n length of the code
+ * @param t error correction capability of the code
+ * @param encMatrix encoded generator matrix
+ */
+ public McElieceCCA2PublicKeySpec(String oid, int n, int t, byte[] encMatrix)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.matrixG = new GF2Matrix(encMatrix);
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getMatrixG()
+ {
+ return matrixG;
+ }
+
+ public String getOIDString()
+ {
+ return oid;
+
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McEliecePrivateKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McEliecePrivateKeySpec.java
new file mode 100644
index 000000000..6515ef934
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McEliecePrivateKeySpec.java
@@ -0,0 +1,201 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+
+import java.security.spec.KeySpec;
+
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.spongycastle.pqc.math.linearalgebra.GF2mField;
+import org.spongycastle.pqc.math.linearalgebra.Permutation;
+import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+/**
+ * This class provides a specification for a McEliece private key.
+ *
+ * @see org.spongycastle.pqc.ecc.JDKMcEliecePrivateKey.McEliecePrivateKey
+ * @see KeySpec
+ */
+public class McEliecePrivateKeySpec
+ implements KeySpec
+{
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the dimension of the code, where <tt>k &gt;= n - mt</tt>
+ private int k;
+
+ // the underlying finite field
+ private GF2mField field;
+
+ // the irreducible Goppa polynomial
+ private PolynomialGF2mSmallM goppaPoly;
+
+ // a k x k random binary non-singular matrix
+ private GF2Matrix sInv;
+
+ // the permutation used to generate the systematic check matrix
+ private Permutation p1;
+
+ // the permutation used to compute the public generator matrix
+ private Permutation p2;
+
+ // the canonical check matrix of the code
+ private GF2Matrix h;
+
+ // the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
+ private PolynomialGF2mSmallM[] qInv;
+
+ /**
+ * Constructor.
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param field the field polynomial defining the finite field
+ * <tt>GF(2<sup>m</sup>)</tt>
+ * @param goppaPoly the irreducible Goppa polynomial
+ * @param sInv the matrix <tt>S<sup>-1</sup></tt>
+ * @param p1 the permutation used to generate the systematic check
+ * matrix
+ * @param p2 the permutation used to compute the public generator
+ * matrix
+ * @param h the canonical check matrix
+ * @param qInv the matrix used to compute square roots in
+ * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
+ */
+ public McEliecePrivateKeySpec(String oid, int n, int k, GF2mField field,
+ PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1,
+ Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv)
+ {
+ this.oid = oid;
+ this.k = k;
+ this.n = n;
+ this.field = field;
+ this.goppaPoly = goppaPoly;
+ this.sInv = sInv;
+ this.p1 = p1;
+ this.p2 = p2;
+ this.h = h;
+ this.qInv = qInv;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceKeyFactory}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param encField the encoded field polynomial defining the finite field
+ * <tt>GF(2<sup>m</sup>)</tt>
+ * @param encGoppaPoly the encoded irreducible Goppa polynomial
+ * @param encSInv the encoded matrix <tt>S<sup>-1</sup></tt>
+ * @param encP1 the encoded permutation used to generate the systematic
+ * check matrix
+ * @param encP2 the encoded permutation used to compute the public
+ * generator matrix
+ * @param encH the encoded canonical check matrix
+ * @param encQInv the encoded matrix used to compute square roots in
+ * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
+ */
+ public McEliecePrivateKeySpec(String oid, int n, int k, byte[] encField,
+ byte[] encGoppaPoly, byte[] encSInv, byte[] encP1, byte[] encP2,
+ byte[] encH, byte[][] encQInv)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ field = new GF2mField(encField);
+ goppaPoly = new PolynomialGF2mSmallM(field, encGoppaPoly);
+ sInv = new GF2Matrix(encSInv);
+ p1 = new Permutation(encP1);
+ p2 = new Permutation(encP2);
+ h = new GF2Matrix(encH);
+ qInv = new PolynomialGF2mSmallM[encQInv.length];
+ for (int i = 0; i < encQInv.length; i++)
+ {
+ qInv[i] = new PolynomialGF2mSmallM(field, encQInv[i]);
+ }
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return k;
+ }
+
+ /**
+ * @return the finite field <tt>GF(2<sup>m</sup>)</tt>
+ */
+ public GF2mField getField()
+ {
+ return field;
+ }
+
+ /**
+ * @return the irreducible Goppa polynomial
+ */
+ public PolynomialGF2mSmallM getGoppaPoly()
+ {
+ return goppaPoly;
+ }
+
+ /**
+ * @return the k x k random binary non-singular matrix S^-1
+ */
+ public GF2Matrix getSInv()
+ {
+ return sInv;
+ }
+
+ /**
+ * @return the permutation used to generate the systematic check matrix
+ */
+ public Permutation getP1()
+ {
+ return p1;
+ }
+
+ /**
+ * @return the permutation used to compute the public generator matrix
+ */
+ public Permutation getP2()
+ {
+ return p2;
+ }
+
+ /**
+ * @return the canonical check matrix H
+ */
+ public GF2Matrix getH()
+ {
+ return h;
+ }
+
+ /**
+ * @return the matrix used to compute square roots in
+ * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
+ */
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ return qInv;
+ }
+
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McEliecePublicKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McEliecePublicKeySpec.java
new file mode 100644
index 000000000..14797446f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/McEliecePublicKeySpec.java
@@ -0,0 +1,91 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+
+import java.security.spec.KeySpec;
+
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+
+/**
+ * This class provides a specification for a McEliece public key.
+ *
+ * @see org.spongycastle.pqc.jcajce.provider.mceliece.BCMcEliecePublicKey
+ */
+public class McEliecePublicKeySpec
+ implements KeySpec
+{
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the error correction capability of the code
+ private int t;
+
+ // the generator matrix
+ private GF2Matrix g;
+
+ /**
+ * Constructor (used by {@link org.spongycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param t the error correction capability of the code
+ * @param g the generator matrix
+ */
+ public McEliecePublicKeySpec(String oid, int n, int t, GF2Matrix g)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.g = new GF2Matrix(g);
+ }
+
+ /**
+ * Constructor (used by {@link org.spongycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param t the error correction capability of the code
+ * @param encG the encoded generator matrix
+ */
+ public McEliecePublicKeySpec(String oid, int t, int n, byte[] encG)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.g = new GF2Matrix(encG);
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getG()
+ {
+ return g;
+ }
+
+ public String getOIDString()
+ {
+ return oid;
+
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowParameterSpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowParameterSpec.java
new file mode 100644
index 000000000..936c00462
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowParameterSpec.java
@@ -0,0 +1,123 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.util.Arrays;
+
+/**
+ * This class provides methods for setting and getting the Rainbow-parameters
+ * like number of Vinegar-variables in the layers, number of layers and so on.
+ * <p/>
+ * More detailed information about the needed parameters for the Rainbow
+ * Signature Scheme is to be found in the paper of Jintai Ding, Dieter Schmidt:
+ * Rainbow, a New Multivariable Polynomial Signature Scheme. ACNS 2005: 164-175
+ * (http://dx.doi.org/10.1007/11496137_12)
+ */
+public class RainbowParameterSpec
+ implements AlgorithmParameterSpec
+{
+
+ /**
+ * DEFAULT PARAMS
+ */
+ /*
+ * Vi = vinegars per layer whereas n is vu (vu = 33 = n) such that
+ *
+ * v1 = 6; o1 = 12-6 = 6
+ *
+ * v2 = 12; o2 = 17-12 = 5
+ *
+ * v3 = 17; o3 = 22-17 = 5
+ *
+ * v4 = 22; o4 = 33-22 = 11
+ *
+ * v5 = 33; (o5 = 0)
+ */
+ private static final int[] DEFAULT_VI = {6, 12, 17, 22, 33};
+
+ private int[] vi;// set of vinegar vars per layer.
+
+ /**
+ * Default Constructor The elements of the array containing the number of
+ * Vinegar variables in each layer are set to the default values here.
+ */
+ public RainbowParameterSpec()
+ {
+ this.vi = DEFAULT_VI;
+ }
+
+ /**
+ * Constructor with parameters
+ *
+ * @param vi The elements of the array containing the number of Vinegar
+ * variables per layer are set to the values of the input array.
+ * @throws IllegalArgumentException if the variables are invalid.
+ */
+ public RainbowParameterSpec(int[] vi)
+ {
+ this.vi = vi;
+ try
+ {
+ checkParams();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private void checkParams()
+ throws Exception
+ {
+ if (vi == null)
+ {
+ throw new IllegalArgumentException("no layers defined.");
+ }
+ if (vi.length > 1)
+ {
+ for (int i = 0; i < vi.length - 1; i++)
+ {
+ if (vi[i] >= vi[i + 1])
+ {
+ throw new IllegalArgumentException(
+ "v[i] has to be smaller than v[i+1]");
+ }
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "Rainbow needs at least 1 layer, such that v1 < v2.");
+ }
+ }
+
+ /**
+ * Getter for the number of layers
+ *
+ * @return the number of layers
+ */
+ public int getNumOfLayers()
+ {
+ return this.vi.length - 1;
+ }
+
+ /**
+ * Getter for the number of all the polynomials in Rainbow
+ *
+ * @return the number of the polynomials
+ */
+ public int getDocumentLength()
+ {
+ return vi[vi.length - 1] - vi[0];
+ }
+
+ /**
+ * Getter for the array containing the number of Vinegar-variables per layer
+ *
+ * @return the numbers of vinegars per layer
+ */
+ public int[] getVi()
+ {
+ return Arrays.clone(this.vi);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowPrivateKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowPrivateKeySpec.java
new file mode 100644
index 000000000..8c854f5da
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowPrivateKeySpec.java
@@ -0,0 +1,125 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+import java.security.spec.KeySpec;
+
+import org.spongycastle.pqc.crypto.rainbow.Layer;
+
+/**
+ * This class provides a specification for a RainbowSignature private key.
+ *
+ * @see KeySpec
+ */
+public class RainbowPrivateKeySpec
+ implements KeySpec
+{
+ /*
+ * invertible affine linear map L1
+ */
+ // the inverse of A1, (n-v1 x n-v1 matrix)
+ private short[][] A1inv;
+
+ // translation vector of L1
+ private short[] b1;
+
+ /*
+ * invertible affine linear map L2
+ */
+ // the inverse of A2, (n x n matrix)
+ private short[][] A2inv;
+
+ // translation vector of L2
+ private short[] b2;
+
+ /*
+ * components of F
+ */
+ // the number of Vinegar-variables per layer.
+ private int[] vi;
+
+ // contains the polynomials with their coefficients of private map F
+ private Layer[] layers;
+
+ /**
+ * Constructor
+ *
+ * @param A1inv the inverse of A1(the matrix part of the affine linear map L1)
+ * (n-v1 x n-v1 matrix)
+ * @param b1 translation vector, part of the linear affine map L1
+ * @param A2inv the inverse of A2(the matrix part of the affine linear map L2)
+ * (n x n matrix)
+ * @param b2 translation vector, part of the linear affine map L2
+ * @param vi the number of Vinegar-variables per layer
+ * @param layers the polynomials with their coefficients of private map F
+ */
+ public RainbowPrivateKeySpec(short[][] A1inv, short[] b1,
+ short[][] A2inv, short[] b2, int[] vi, Layer[] layers)
+ {
+ this.A1inv = A1inv;
+ this.b1 = b1;
+ this.A2inv = A2inv;
+ this.b2 = b2;
+ this.vi = vi;
+ this.layers = layers;
+ }
+
+ /**
+ * Getter for the translation part of the private quadratic map L1.
+ *
+ * @return b1 the translation part of L1
+ */
+ public short[] getB1()
+ {
+ return this.b1;
+ }
+
+ /**
+ * Getter for the inverse matrix of A1.
+ *
+ * @return the A1inv inverse
+ */
+ public short[][] getInvA1()
+ {
+ return this.A1inv;
+ }
+
+ /**
+ * Getter for the translation part of the private quadratic map L2.
+ *
+ * @return b2 the translation part of L2
+ */
+ public short[] getB2()
+ {
+ return this.b2;
+ }
+
+ /**
+ * Getter for the inverse matrix of A2
+ *
+ * @return the A2inv
+ */
+ public short[][] getInvA2()
+ {
+ return this.A2inv;
+ }
+
+ /**
+ * Returns the layers contained in the private key
+ *
+ * @return layers
+ */
+ public Layer[] getLayers()
+ {
+ return this.layers;
+ }
+
+ /**
+ * /** Returns the array of vi-s
+ *
+ * @return the vi
+ */
+ public int[] getVi()
+ {
+ return vi;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowPublicKeySpec.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowPublicKeySpec.java
new file mode 100644
index 000000000..ce79e9ab0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/spec/RainbowPublicKeySpec.java
@@ -0,0 +1,68 @@
+package org.spongycastle.pqc.jcajce.spec;
+
+
+import java.security.spec.KeySpec;
+
+/**
+ * This class provides a specification for a RainbowSignature public key.
+ *
+ * @see KeySpec
+ */
+public class RainbowPublicKeySpec
+ implements KeySpec
+{
+ private short[][] coeffquadratic;
+ private short[][] coeffsingular;
+ private short[] coeffscalar;
+ private int docLength; // length of possible document to sign
+
+ /**
+ * Constructor
+ *
+ * @param docLength
+ * @param coeffquadratic
+ * @param coeffSingular
+ * @param coeffScalar
+ */
+ public RainbowPublicKeySpec(int docLength,
+ short[][] coeffquadratic, short[][] coeffSingular,
+ short[] coeffScalar)
+ {
+ this.docLength = docLength;
+ this.coeffquadratic = coeffquadratic;
+ this.coeffsingular = coeffSingular;
+ this.coeffscalar = coeffScalar;
+ }
+
+ /**
+ * @return the docLength
+ */
+ public int getDocLength()
+ {
+ return this.docLength;
+ }
+
+ /**
+ * @return the coeffquadratic
+ */
+ public short[][] getCoeffQuadratic()
+ {
+ return coeffquadratic;
+ }
+
+ /**
+ * @return the coeffsingular
+ */
+ public short[][] getCoeffSingular()
+ {
+ return coeffsingular;
+ }
+
+ /**
+ * @return the coeffscalar
+ */
+ public short[] getCoeffScalar()
+ {
+ return coeffscalar;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/AttributeCertificateHolder.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/AttributeCertificateHolder.java
new file mode 100644
index 000000000..981a7203e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/AttributeCertificateHolder.java
@@ -0,0 +1,420 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.Holder;
+import org.spongycastle.asn1.x509.IssuerSerial;
+import org.spongycastle.asn1.x509.ObjectDigestInfo;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+
+/**
+ * The Holder object.
+ *
+ * <pre>
+ * Holder ::= SEQUENCE {
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * -- the issuer and serial number of
+ * -- the holder's Public Key Certificate
+ * entityName [1] GeneralNames OPTIONAL,
+ * -- the name of the claimant or role
+ * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ * -- used to directly authenticate the holder,
+ * -- for example, an executable
+ * }
+ * </pre>
+ * @deprecated use org.spongycastle.cert.AttributeCertificateHolder
+ */
+public class AttributeCertificateHolder
+ implements CertSelector, Selector
+{
+ final Holder holder;
+
+ AttributeCertificateHolder(ASN1Sequence seq)
+ {
+ holder = Holder.getInstance(seq);
+ }
+
+ public AttributeCertificateHolder(X509Principal issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new org.spongycastle.asn1.x509.Holder(new IssuerSerial(
+ GeneralNames.getInstance(new DERSequence(new GeneralName(issuerName))),
+ new ASN1Integer(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(X500Principal issuerName,
+ BigInteger serialNumber)
+ {
+ this(X509Util.convertPrincipal(issuerName), serialNumber);
+ }
+
+ public AttributeCertificateHolder(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ X509Principal name;
+
+ try
+ {
+ name = PrincipalUtil.getIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+
+ holder = new Holder(new IssuerSerial(generateGeneralNames(name),
+ new ASN1Integer(cert.getSerialNumber())));
+ }
+
+ public AttributeCertificateHolder(X509Principal principal)
+ {
+ holder = new Holder(generateGeneralNames(principal));
+ }
+
+ public AttributeCertificateHolder(X500Principal principal)
+ {
+ this(X509Util.convertPrincipal(principal));
+ }
+
+ /**
+ * Constructs a holder for v2 attribute certificates with a hash value for
+ * some type of object.
+ * <p>
+ * <code>digestedObjectType</code> can be one of the following:
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ * <p>
+ * This cannot be used if a v1 attribute certificate is used.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param otherObjectTypeID The object type ID if
+ * <code>digestedObjectType</code> is
+ * <code>otherObjectDigest</code>.
+ * @param objectDigest The hash value.
+ */
+ public AttributeCertificateHolder(int digestedObjectType,
+ String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)
+ {
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType,
+ new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(digestAlgorithm), Arrays
+ .clone(objectDigest)));
+ }
+
+ /**
+ * Returns the digest object type if an object digest info is used.
+ * <p>
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ *
+ * @return The digest object type or -1 if no object digest info is set.
+ */
+ public int getDigestedObjectType()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestedObjectType()
+ .getValue().intValue();
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the other object type ID if an object digest info is used.
+ *
+ * @return The other object type ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getDigestAlgorithm()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId()
+ .getId();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or <code>null</code> if no object digest info is set.
+ */
+ public byte[] getObjectDigest()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getObjectDigest().getBytes();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the digest algorithm ID if an object digest info is used.
+ *
+ * @return The digest algorithm ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getOtherObjectTypeID()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
+ }
+ return null;
+ }
+
+ private GeneralNames generateGeneralNames(X509Principal principal)
+ {
+ return GeneralNames.getInstance(new DERSequence(new GeneralName(principal)));
+ }
+
+ private boolean matchesDN(X509Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
+ .getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private Object[] getNames(GeneralName[] names)
+ {
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X500Principal(
+ ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ private Principal[] getPrincipals(GeneralNames names)
+ {
+ Object[] p = this.getNames(names.getNames());
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate holder
+ * entity names field.
+ *
+ * @return an array of Principal objects (usually X500Principal), null if no
+ * entity names field is set.
+ */
+ public Principal[] getEntityNames()
+ {
+ if (holder.getEntityName() != null)
+ {
+ return getPrincipals(holder.getEntityName());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the principals associated with the issuer attached to this holder
+ *
+ * @return an array of principals, null if no BaseCertificateID is set.
+ */
+ public Principal[] getIssuer()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return getPrincipals(holder.getBaseCertificateID().getIssuer());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the serial number associated with the issuer attached to this
+ * holder.
+ *
+ * @return the certificate serial number, null if no BaseCertificateID is
+ * set.
+ */
+ public BigInteger getSerialNumber()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue();
+ }
+
+ return null;
+ }
+
+ public Object clone()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)holder
+ .toASN1Object());
+ }
+
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
+ }
+
+ if (holder.getEntityName() != null)
+ {
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert),
+ holder.getEntityName()))
+ {
+ return true;
+ }
+ }
+ if (holder.getObjectDigestInfo() != null)
+ {
+ MessageDigest md = null;
+ try
+ {
+ md = MessageDigest.getInstance(getDigestAlgorithm(), "SC");
+
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ switch (getDigestedObjectType())
+ {
+ case ObjectDigestInfo.publicKey:
+ // TODO: DSA Dss-parms
+ md.update(cert.getPublicKey().getEncoded());
+ break;
+ case ObjectDigestInfo.publicKeyCert:
+ md.update(cert.getEncoded());
+ break;
+ }
+ if (!Arrays.areEqual(md.digest(), getObjectDigest()))
+ {
+ return false;
+ }
+ }
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+ return this.holder.equals(other.holder);
+ }
+
+ public int hashCode()
+ {
+ return this.holder.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/AttributeCertificateIssuer.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/AttributeCertificateIssuer.java
new file mode 100644
index 000000000..3a96e05b5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/AttributeCertificateIssuer.java
@@ -0,0 +1,208 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AttCertIssuer;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.V2Form;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.Selector;
+
+/**
+ * Carrying class for an attribute certificate issuer.
+ * @deprecated use org.spongycastle.cert.AttributeCertificateIssuer
+ */
+public class AttributeCertificateIssuer
+ implements CertSelector, Selector
+{
+ final ASN1Encodable form;
+
+ /**
+ * Set the issuer directly with the ASN.1 structure.
+ *
+ * @param issuer The issuer
+ */
+ public AttributeCertificateIssuer(AttCertIssuer issuer)
+ {
+ form = issuer.getIssuer();
+ }
+
+ public AttributeCertificateIssuer(X500Principal principal)
+ throws IOException
+ {
+ this(new X509Principal(principal.getEncoded()));
+ }
+
+ public AttributeCertificateIssuer(X509Principal principal)
+ {
+ form = new V2Form(GeneralNames.getInstance(new DERSequence(new GeneralName(principal))));
+ }
+
+ private Object[] getNames()
+ {
+ GeneralNames name;
+
+ if (form instanceof V2Form)
+ {
+ name = ((V2Form)form).getIssuerName();
+ }
+ else
+ {
+ name = (GeneralNames)form;
+ }
+
+ GeneralName[] names = name.getNames();
+
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X500Principal(
+ ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate issuer
+ * object.
+ *
+ * @return an array of Principal objects (usually X500Principal)
+ */
+ public Principal[] getPrincipals()
+ {
+ Object[] p = this.getNames();
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ private boolean matchesDN(X500Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X500Principal(((ASN1Encodable)gn.getName()).toASN1Primitive().getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public Object clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));
+ }
+
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ if (form instanceof V2Form)
+ {
+ V2Form issuer = (V2Form)form;
+ if (issuer.getBaseCertificateID() != null)
+ {
+ return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(x509Cert.getIssuerX500Principal(), issuer.getBaseCertificateID().getIssuer());
+ }
+
+ GeneralNames name = issuer.getIssuerName();
+ if (matchesDN(x509Cert.getSubjectX500Principal(), name))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ GeneralNames name = (GeneralNames)form;
+ if (matchesDN(x509Cert.getSubjectX500Principal(), name))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateIssuer))
+ {
+ return false;
+ }
+
+ AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+ return this.form.equals(other.form);
+ }
+
+ public int hashCode()
+ {
+ return this.form.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/CertPathReviewerException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/CertPathReviewerException.java
new file mode 100644
index 000000000..ddf89748e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/CertPathReviewerException.java
@@ -0,0 +1,72 @@
+package org.spongycastle.x509;
+
+import java.security.cert.CertPath;
+
+import org.spongycastle.i18n.ErrorBundle;
+import org.spongycastle.i18n.LocalizedException;
+
+public class CertPathReviewerException extends LocalizedException
+{
+
+ private int index = -1;
+
+ private CertPath certPath = null;
+
+ public CertPathReviewerException(ErrorBundle errorMessage, Throwable throwable)
+ {
+ super(errorMessage, throwable);
+ }
+
+ public CertPathReviewerException(ErrorBundle errorMessage)
+ {
+ super(errorMessage);
+ }
+
+ public CertPathReviewerException(
+ ErrorBundle errorMessage,
+ Throwable throwable,
+ CertPath certPath,
+ int index)
+ {
+ super(errorMessage, throwable);
+ if (certPath == null || index == -1)
+ {
+ throw new IllegalArgumentException();
+ }
+ if (index < -1 || (certPath != null && index >= certPath.getCertificates().size()))
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ this.certPath = certPath;
+ this.index = index;
+ }
+
+ public CertPathReviewerException(
+ ErrorBundle errorMessage,
+ CertPath certPath,
+ int index)
+ {
+ super(errorMessage);
+ if (certPath == null || index == -1)
+ {
+ throw new IllegalArgumentException();
+ }
+ if (index < -1 || (certPath != null && index >= certPath.getCertificates().size()))
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ this.certPath = certPath;
+ this.index = index;
+ }
+
+ public CertPath getCertPath()
+ {
+ return certPath;
+ }
+
+ public int getIndex()
+ {
+ return index;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtCertificateEncodingException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtCertificateEncodingException.java
new file mode 100644
index 000000000..ec3511a93
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtCertificateEncodingException.java
@@ -0,0 +1,20 @@
+package org.spongycastle.x509;
+
+import java.security.cert.CertificateEncodingException;
+
+class ExtCertificateEncodingException
+ extends CertificateEncodingException
+{
+ Throwable cause;
+
+ ExtCertificateEncodingException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java
new file mode 100644
index 000000000..5299d5cfa
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java
@@ -0,0 +1,210 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class contains extended parameters for PKIX certification path builders.
+ *
+ * @see java.security.cert.PKIXBuilderParameters
+ * @see org.spongycastle.jce.provider.PKIXCertPathBuilderSpi
+ */
+public class ExtendedPKIXBuilderParameters extends ExtendedPKIXParameters
+{
+
+ private int maxPathLength = 5;
+
+ private Set excludedCerts = Collections.EMPTY_SET;
+
+ /**
+ * Excluded certificates are not used for building a certification path.
+ * <p>
+ * The returned set is immutable.
+ *
+ * @return Returns the excluded certificates.
+ */
+ public Set getExcludedCerts()
+ {
+ return Collections.unmodifiableSet(excludedCerts);
+ }
+
+ /**
+ * Sets the excluded certificates which are not used for building a
+ * certification path. If the <code>Set</code> is <code>null</code> an
+ * empty set is assumed.
+ * <p>
+ * The given set is cloned to protect it against subsequent modifications.
+ *
+ * @param excludedCerts The excluded certificates to set.
+ */
+ public void setExcludedCerts(Set excludedCerts)
+ {
+ if (excludedCerts == null)
+ {
+ excludedCerts = Collections.EMPTY_SET;
+ }
+ else
+ {
+ this.excludedCerts = new HashSet(excludedCerts);
+ }
+ }
+
+ /**
+ * Creates an instance of <code>PKIXBuilderParameters</code> with the
+ * specified <code>Set</code> of most-trusted CAs. Each element of the set
+ * is a {@link TrustAnchor TrustAnchor}.
+ *
+ * <p>
+ * Note that the <code>Set</code> is copied to protect against subsequent
+ * modifications.
+ *
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+ * @param targetConstraints a <code>Selector</code> specifying the
+ * constraints on the target certificate or attribute
+ * certificate.
+ * @throws InvalidAlgorithmParameterException if <code>trustAnchors</code>
+ * is empty.
+ * @throws NullPointerException if <code>trustAnchors</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements of
+ * <code>trustAnchors</code> is not of type
+ * <code>java.security.cert.TrustAnchor</code>
+ */
+ public ExtendedPKIXBuilderParameters(Set trustAnchors,
+ Selector targetConstraints)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ setTargetConstraints(targetConstraints);
+ }
+
+ /**
+ * Sets the maximum number of intermediate non-self-issued certificates in a
+ * certification path. The PKIX <code>CertPathBuilder</code> must not
+ * build paths longer then this length.
+ * <p>
+ * A value of 0 implies that the path can only contain a single certificate.
+ * A value of -1 does not limit the length. The default length is 5.
+ *
+ * <p>
+ *
+ * The basic constraints extension of a CA certificate overrides this value
+ * if smaller.
+ *
+ * @param maxPathLength the maximum number of non-self-issued intermediate
+ * certificates in the certification path
+ * @throws InvalidParameterException if <code>maxPathLength</code> is set
+ * to a value less than -1
+ *
+ * @see org.spongycastle.jce.provider.PKIXCertPathBuilderSpi
+ * @see #getMaxPathLength
+ */
+ public void setMaxPathLength(int maxPathLength)
+ {
+ if (maxPathLength < -1)
+ {
+ throw new InvalidParameterException("The maximum path "
+ + "length parameter can not be less than -1.");
+ }
+ this.maxPathLength = maxPathLength;
+ }
+
+ /**
+ * Returns the value of the maximum number of intermediate non-self-issued
+ * certificates in the certification path.
+ *
+ * @return the maximum number of non-self-issued intermediate certificates
+ * in the certification path, or -1 if no limit exists.
+ *
+ * @see #setMaxPathLength(int)
+ */
+ public int getMaxPathLength()
+ {
+ return maxPathLength;
+ }
+
+ /**
+ * Can alse handle <code>ExtendedPKIXBuilderParameters</code> and
+ * <code>PKIXBuilderParameters</code>.
+ *
+ * @param params Parameters to set.
+ * @see org.spongycastle.x509.ExtendedPKIXParameters#setParams(java.security.cert.PKIXParameters)
+ */
+ protected void setParams(PKIXParameters params)
+ {
+ super.setParams(params);
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ ExtendedPKIXBuilderParameters _params = (ExtendedPKIXBuilderParameters) params;
+ maxPathLength = _params.maxPathLength;
+ excludedCerts = new HashSet(_params.excludedCerts);
+ }
+ if (params instanceof PKIXBuilderParameters)
+ {
+ PKIXBuilderParameters _params = (PKIXBuilderParameters) params;
+ maxPathLength = _params.getMaxPathLength();
+ }
+ }
+
+ /**
+ * Makes a copy of this <code>PKIXParameters</code> object. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this <code>PKIXParameters</code> object
+ */
+ public Object clone()
+ {
+ ExtendedPKIXBuilderParameters params = null;
+ try
+ {
+ params = new ExtendedPKIXBuilderParameters(getTrustAnchors(),
+ getTargetConstraints());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(this);
+ return params;
+ }
+
+ /**
+ * Returns an instance of <code>ExtendedPKIXParameters</code> which can be
+ * safely casted to <code>ExtendedPKIXBuilderParameters</code>.
+ * <p>
+ * This method can be used to get a copy from other
+ * <code>PKIXBuilderParameters</code>, <code>PKIXParameters</code>,
+ * and <code>ExtendedPKIXParameters</code> instances.
+ *
+ * @param pkixParams The PKIX parameters to create a copy of.
+ * @return An <code>ExtendedPKIXBuilderParameters</code> instance.
+ */
+ public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+ {
+ ExtendedPKIXBuilderParameters params;
+ try
+ {
+ params = new ExtendedPKIXBuilderParameters(pkixParams
+ .getTrustAnchors(), X509CertStoreSelector
+ .getInstance((X509CertSelector) pkixParams
+ .getTargetCertConstraints()));
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(pkixParams);
+ return params;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtendedPKIXParameters.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtendedPKIXParameters.java
new file mode 100644
index 000000000..12cef95da
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/ExtendedPKIXParameters.java
@@ -0,0 +1,651 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.Store;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class extends the PKIXParameters with a validity model parameter.
+ */
+public class ExtendedPKIXParameters
+ extends PKIXParameters
+{
+
+ private List stores;
+
+ private Selector selector;
+
+ private boolean additionalLocationsEnabled;
+
+ private List additionalStores;
+
+ private Set trustedACIssuers;
+
+ private Set necessaryACAttributes;
+
+ private Set prohibitedACAttributes;
+
+ private Set attrCertCheckers;
+
+ /**
+ * Creates an instance of <code>PKIXParameters</code> with the specified
+ * <code>Set</code> of most-trusted CAs. Each element of the set is a
+ * {@link TrustAnchor TrustAnchor}. <p/> Note that the <code>Set</code>
+ * is copied to protect against subsequent modifications.
+ *
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+ * @throws InvalidAlgorithmParameterException if the specified
+ * <code>Set</code> is empty.
+ * @throws NullPointerException if the specified <code>Set</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements in the <code>Set</code>
+ * is not of type <code>java.security.cert.TrustAnchor</code>
+ */
+ public ExtendedPKIXParameters(Set trustAnchors)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ stores = new ArrayList();
+ additionalStores = new ArrayList();
+ trustedACIssuers = new HashSet();
+ necessaryACAttributes = new HashSet();
+ prohibitedACAttributes = new HashSet();
+ attrCertCheckers = new HashSet();
+ }
+
+ /**
+ * Returns an instance with the parameters of a given
+ * <code>PKIXParameters</code> object.
+ *
+ * @param pkixParams The given <code>PKIXParameters</code>
+ * @return an extended PKIX params object
+ */
+ public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+ {
+ ExtendedPKIXParameters params;
+ try
+ {
+ params = new ExtendedPKIXParameters(pkixParams.getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(pkixParams);
+ return params;
+ }
+
+ /**
+ * Method to support <code>clone()</code> under J2ME.
+ * <code>super.clone()</code> does not exist and fields are not copied.
+ *
+ * @param params Parameters to set. If this are
+ * <code>ExtendedPKIXParameters</code> they are copied to.
+ */
+ protected void setParams(PKIXParameters params)
+ {
+ setDate(params.getDate());
+ setCertPathCheckers(params.getCertPathCheckers());
+ setCertStores(params.getCertStores());
+ setAnyPolicyInhibited(params.isAnyPolicyInhibited());
+ setExplicitPolicyRequired(params.isExplicitPolicyRequired());
+ setPolicyMappingInhibited(params.isPolicyMappingInhibited());
+ setRevocationEnabled(params.isRevocationEnabled());
+ setInitialPolicies(params.getInitialPolicies());
+ setPolicyQualifiersRejected(params.getPolicyQualifiersRejected());
+ setSigProvider(params.getSigProvider());
+ setTargetCertConstraints(params.getTargetCertConstraints());
+ try
+ {
+ setTrustAnchors(params.getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ if (params instanceof ExtendedPKIXParameters)
+ {
+ ExtendedPKIXParameters _params = (ExtendedPKIXParameters) params;
+ validityModel = _params.validityModel;
+ useDeltas = _params.useDeltas;
+ additionalLocationsEnabled = _params.additionalLocationsEnabled;
+ selector = _params.selector == null ? null
+ : (Selector) _params.selector.clone();
+ stores = new ArrayList(_params.stores);
+ additionalStores = new ArrayList(_params.additionalStores);
+ trustedACIssuers = new HashSet(_params.trustedACIssuers);
+ prohibitedACAttributes = new HashSet(_params.prohibitedACAttributes);
+ necessaryACAttributes = new HashSet(_params.necessaryACAttributes);
+ attrCertCheckers = new HashSet(_params.attrCertCheckers);
+ }
+ }
+
+ /**
+ * This is the default PKIX validity model. Actually there are two variants
+ * of this: The PKIX model and the modified PKIX model. The PKIX model
+ * verifies that all involved certificates must have been valid at the
+ * current time. The modified PKIX model verifies that all involved
+ * certificates were valid at the signing time. Both are indirectly choosen
+ * with the {@link PKIXParameters#setDate(java.util.Date)} method, so this
+ * methods sets the Date when <em>all</em> certificates must have been
+ * valid.
+ */
+ public static final int PKIX_VALIDITY_MODEL = 0;
+
+ /**
+ * This model uses the following validity model. Each certificate must have
+ * been valid at the moment where is was used. That means the end
+ * certificate must have been valid at the time the signature was done. The
+ * CA certificate which signed the end certificate must have been valid,
+ * when the end certificate was signed. The CA (or Root CA) certificate must
+ * have been valid, when the CA certificate was signed and so on. So the
+ * {@link PKIXParameters#setDate(java.util.Date)} method sets the time, when
+ * the <em>end certificate</em> must have been valid. <p/> It is used e.g.
+ * in the German signature law.
+ */
+ public static final int CHAIN_VALIDITY_MODEL = 1;
+
+ private int validityModel = PKIX_VALIDITY_MODEL;
+
+ private boolean useDeltas = false;
+
+ /**
+ * Defaults to <code>false</code>.
+ *
+ * @return Returns if delta CRLs should be used.
+ */
+ public boolean isUseDeltasEnabled()
+ {
+ return useDeltas;
+ }
+
+ /**
+ * Sets if delta CRLs should be used for checking the revocation status.
+ *
+ * @param useDeltas <code>true</code> if delta CRLs should be used.
+ */
+ public void setUseDeltasEnabled(boolean useDeltas)
+ {
+ this.useDeltas = useDeltas;
+ }
+
+ /**
+ * @return Returns the validity model.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public int getValidityModel()
+ {
+ return validityModel;
+ }
+
+ /**
+ * Sets the Java CertStore to this extended PKIX parameters.
+ *
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>CertStore</code>.
+ */
+ public void setCertStores(List stores)
+ {
+ if (stores != null)
+ {
+ Iterator it = stores.iterator();
+ while (it.hasNext())
+ {
+ addCertStore((CertStore)it.next());
+ }
+ }
+ }
+
+ /**
+ * Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * The <code>List</code> is cloned.
+ *
+ * @param stores A list of stores to use.
+ * @see #getStores
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a {@link Store}.
+ */
+ public void setStores(List stores)
+ {
+ if (stores == null)
+ {
+ this.stores = new ArrayList();
+ }
+ else
+ {
+ for (Iterator i = stores.iterator(); i.hasNext();)
+ {
+ if (!(i.next() instanceof Store))
+ {
+ throw new ClassCastException(
+ "All elements of list must be "
+ + "of type org.spongycastle.util.Store.");
+ }
+ }
+ this.stores = new ArrayList(stores);
+ }
+ }
+
+ /**
+ * Adds a Bouncy Castle {@link Store} to find CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * This method should be used to add local stores, like collection based
+ * X.509 stores, if available. Local stores should be considered first,
+ * before trying to use additional (remote) locations, because they do not
+ * need possible additional network traffic.
+ * <p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ *
+ * @param store The store to add.
+ * @see #getStores
+ */
+ public void addStore(Store store)
+ {
+ if (store != null)
+ {
+ stores.add(store);
+ }
+ }
+
+ /**
+ * Adds an additional Bouncy Castle {@link Store} to find CRLs, certificates,
+ * attribute certificates or cross certificates.
+ * <p>
+ * You should not use this method. This method is used for adding additional
+ * X.509 stores, which are used to add (remote) locations, e.g. LDAP, found
+ * during X.509 object processing, e.g. in certificates or CRLs. This method
+ * is used in PKIX certification path processing.
+ * <p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ *
+ * @param store The store to add.
+ * @see #getStores()
+ */
+ public void addAdditionalStore(Store store)
+ {
+ if (store != null)
+ {
+ additionalStores.add(store);
+ }
+ }
+
+ /**
+ * @deprecated
+ */
+ public void addAddionalStore(Store store)
+ {
+ addAdditionalStore(store);
+ }
+
+ /**
+ * Returns an immutable <code>List</code> of additional Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>List</code> of additional Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #addAdditionalStore(Store)
+ */
+ public List getAdditionalStores()
+ {
+ return Collections.unmodifiableList(additionalStores);
+ }
+
+ /**
+ * Returns an immutable <code>List</code> of Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>List</code> of Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #setStores(List)
+ */
+ public List getStores()
+ {
+ return Collections.unmodifiableList(new ArrayList(stores));
+ }
+
+ /**
+ * @param validityModel The validity model to set.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public void setValidityModel(int validityModel)
+ {
+ this.validityModel = validityModel;
+ }
+
+ public Object clone()
+ {
+ ExtendedPKIXParameters params;
+ try
+ {
+ params = new ExtendedPKIXParameters(getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(this);
+ return params;
+ }
+
+ /**
+ * Returns if additional {@link X509Store}s for locations like LDAP found
+ * in certificates or CRLs should be used.
+ *
+ * @return Returns <code>true</code> if additional stores are used.
+ */
+ public boolean isAdditionalLocationsEnabled()
+ {
+ return additionalLocationsEnabled;
+ }
+
+ /**
+ * Sets if additional {@link X509Store}s for locations like LDAP found in
+ * certificates or CRLs should be used.
+ *
+ * @param enabled <code>true</code> if additional stores are used.
+ */
+ public void setAdditionalLocationsEnabled(boolean enabled)
+ {
+ additionalLocationsEnabled = enabled;
+ }
+
+ /**
+ * Returns the required constraints on the target certificate or attribute
+ * certificate. The constraints are returned as an instance of
+ * <code>Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ *
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * <p>
+ * Note that the <code>Selector</code> returned is cloned to protect
+ * against subsequent modifications.
+ *
+ * @return a <code>Selector</code> specifying the constraints on the
+ * target certificate or attribute certificate (or <code>null</code>)
+ * @see #setTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public Selector getTargetConstraints()
+ {
+ if (selector != null)
+ {
+ return (Selector) selector.clone();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate or attribute
+ * certificate. The constraints are specified as an instance of
+ * <code>Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * <p>
+ * Note that the <code>Selector</code> specified is cloned to protect
+ * against subsequent modifications.
+ *
+ * @param selector a <code>Selector</code> specifying the constraints on
+ * the target certificate or attribute certificate (or
+ * <code>null</code>)
+ * @see #getTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public void setTargetConstraints(Selector selector)
+ {
+ if (selector != null)
+ {
+ this.selector = (Selector) selector.clone();
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate. The constraints
+ * are specified as an instance of <code>X509CertSelector</code>. If
+ * <code>null</code>, no constraints are defined.
+ *
+ * <p>
+ * This method wraps the given <code>X509CertSelector</code> into a
+ * <code>X509CertStoreSelector</code>.
+ * <p>
+ * Note that the <code>X509CertSelector</code> specified is cloned to
+ * protect against subsequent modifications.
+ *
+ * @param selector a <code>X509CertSelector</code> specifying the
+ * constraints on the target certificate (or <code>null</code>)
+ * @see #getTargetCertConstraints
+ * @see X509CertStoreSelector
+ */
+ public void setTargetCertConstraints(CertSelector selector)
+ {
+ super.setTargetCertConstraints(selector);
+ if (selector != null)
+ {
+ this.selector = X509CertStoreSelector
+ .getInstance((X509CertSelector) selector);
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Returns the trusted attribute certificate issuers. If attribute
+ * certificates is verified the trusted AC issuers must be set.
+ * <p>
+ * The returned <code>Set</code> consists of <code>TrustAnchor</code>s.
+ * <p>
+ * The returned <code>Set</code> is immutable. Never <code>null</code>
+ *
+ * @return Returns an immutable set of the trusted AC issuers.
+ */
+ public Set getTrustedACIssuers()
+ {
+ return Collections.unmodifiableSet(trustedACIssuers);
+ }
+
+ /**
+ * Sets the trusted attribute certificate issuers. If attribute certificates
+ * is verified the trusted AC issuers must be set.
+ * <p>
+ * The <code>trustedACIssuers</code> must be a <code>Set</code> of
+ * <code>TrustAnchor</code>
+ * <p>
+ * The given set is cloned.
+ *
+ * @param trustedACIssuers The trusted AC issuers to set. Is never
+ * <code>null</code>.
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>TrustAnchor</code>.
+ */
+ public void setTrustedACIssuers(Set trustedACIssuers)
+ {
+ if (trustedACIssuers == null)
+ {
+ this.trustedACIssuers.clear();
+ return;
+ }
+ for (Iterator it = trustedACIssuers.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof TrustAnchor))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type " + TrustAnchor.class.getName() + ".");
+ }
+ }
+ this.trustedACIssuers.clear();
+ this.trustedACIssuers.addAll(trustedACIssuers);
+ }
+
+ /**
+ * Returns the neccessary attributes which must be contained in an attribute
+ * certificate.
+ * <p>
+ * The returned <code>Set</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ *
+ * @return Returns the necessary AC attributes.
+ */
+ public Set getNecessaryACAttributes()
+ {
+ return Collections.unmodifiableSet(necessaryACAttributes);
+ }
+
+ /**
+ * Sets the neccessary which must be contained in an attribute certificate.
+ * <p>
+ * The <code>Set</code> must contain <code>String</code>s with the
+ * OIDs.
+ * <p>
+ * The set is cloned.
+ *
+ * @param necessaryACAttributes The necessary AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>necessaryACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public void setNecessaryACAttributes(Set necessaryACAttributes)
+ {
+ if (necessaryACAttributes == null)
+ {
+ this.necessaryACAttributes.clear();
+ return;
+ }
+ for (Iterator it = necessaryACAttributes.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof String))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type String.");
+ }
+ }
+ this.necessaryACAttributes.clear();
+ this.necessaryACAttributes.addAll(necessaryACAttributes);
+ }
+
+ /**
+ * Returns the attribute certificates which are not allowed.
+ * <p>
+ * The returned <code>Set</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ *
+ * @return Returns the prohibited AC attributes. Is never <code>null</code>.
+ */
+ public Set getProhibitedACAttributes()
+ {
+ return Collections.unmodifiableSet(prohibitedACAttributes);
+ }
+
+ /**
+ * Sets the attribute certificates which are not allowed.
+ * <p>
+ * The <code>Set</code> must contain <code>String</code>s with the
+ * OIDs.
+ * <p>
+ * The set is cloned.
+ *
+ * @param prohibitedACAttributes The prohibited AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>prohibitedACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public void setProhibitedACAttributes(Set prohibitedACAttributes)
+ {
+ if (prohibitedACAttributes == null)
+ {
+ this.prohibitedACAttributes.clear();
+ return;
+ }
+ for (Iterator it = prohibitedACAttributes.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof String))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type String.");
+ }
+ }
+ this.prohibitedACAttributes.clear();
+ this.prohibitedACAttributes.addAll(prohibitedACAttributes);
+ }
+
+ /**
+ * Returns the attribute certificate checker. The returned set contains
+ * {@link PKIXAttrCertChecker}s and is immutable.
+ *
+ * @return Returns the attribute certificate checker. Is never
+ * <code>null</code>.
+ */
+ public Set getAttrCertCheckers()
+ {
+ return Collections.unmodifiableSet(attrCertCheckers);
+ }
+
+ /**
+ * Sets the attribute certificate checkers.
+ * <p>
+ * All elements in the <code>Set</code> must a {@link PKIXAttrCertChecker}.
+ * <p>
+ * The given set is cloned.
+ *
+ * @param attrCertCheckers The attribute certificate checkers to set. Is
+ * never <code>null</code>.
+ * @throws ClassCastException if an element of <code>attrCertCheckers</code>
+ * is not a <code>PKIXAttrCertChecker</code>.
+ */
+ public void setAttrCertCheckers(Set attrCertCheckers)
+ {
+ if (attrCertCheckers == null)
+ {
+ this.attrCertCheckers.clear();
+ return;
+ }
+ for (Iterator it = attrCertCheckers.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof PKIXAttrCertChecker))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type " + PKIXAttrCertChecker.class.getName() + ".");
+ }
+ }
+ this.attrCertCheckers.clear();
+ this.attrCertCheckers.addAll(attrCertCheckers);
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/NoSuchParserException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/NoSuchParserException.java
new file mode 100644
index 000000000..060633021
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/NoSuchParserException.java
@@ -0,0 +1,10 @@
+package org.spongycastle.x509;
+
+public class NoSuchParserException
+ extends Exception
+{
+ public NoSuchParserException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/NoSuchStoreException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/NoSuchStoreException.java
new file mode 100644
index 000000000..35d499a2f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/NoSuchStoreException.java
@@ -0,0 +1,10 @@
+package org.spongycastle.x509;
+
+public class NoSuchStoreException
+ extends Exception
+{
+ public NoSuchStoreException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/PKIXAttrCertChecker.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/PKIXAttrCertChecker.java
new file mode 100644
index 000000000..7e4f1cbdd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/PKIXAttrCertChecker.java
@@ -0,0 +1,56 @@
+package org.spongycastle.x509;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.util.Collection;
+import java.util.Set;
+
+public abstract class PKIXAttrCertChecker
+ implements Cloneable
+{
+
+ /**
+ * Returns an immutable <code>Set</code> of X.509 attribute certificate
+ * extensions that this <code>PKIXAttrCertChecker</code> supports or
+ * <code>null</code> if no extensions are supported.
+ * <p>
+ * Each element of the set is a <code>String</code> representing the
+ * Object Identifier (OID) of the X.509 extension that is supported.
+ * <p>
+ * All X.509 attribute certificate extensions that a
+ * <code>PKIXAttrCertChecker</code> might possibly be able to process
+ * should be included in the set.
+ *
+ * @return an immutable <code>Set</code> of X.509 extension OIDs (in
+ * <code>String</code> format) supported by this
+ * <code>PKIXAttrCertChecker</code>, or <code>null</code> if no
+ * extensions are supported
+ */
+ public abstract Set getSupportedExtensions();
+
+ /**
+ * Performs checks on the specified attribute certificate. Every handled
+ * extension is rmeoved from the <code>unresolvedCritExts</code>
+ * collection.
+ *
+ * @param attrCert The attribute certificate to be checked.
+ * @param certPath The certificate path which belongs to the attribute
+ * certificate issuer public key certificate.
+ * @param holderCertPath The certificate path which belongs to the holder
+ * certificate.
+ * @param unresolvedCritExts a <code>Collection</code> of OID strings
+ * representing the current set of unresolved critical extensions
+ * @throws CertPathValidatorException if the specified attribute certificate
+ * does not pass the check.
+ */
+ public abstract void check(X509AttributeCertificate attrCert, CertPath certPath,
+ CertPath holderCertPath, Collection unresolvedCritExts)
+ throws CertPathValidatorException;
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return a copy of this <code>PKIXAttrCertChecker</code>
+ */
+ public abstract Object clone();
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/PKIXCertPathReviewer.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/PKIXCertPathReviewer.java
new file mode 100644
index 000000000..6f8ed6aaf
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/PKIXCertPathReviewer.java
@@ -0,0 +1,2544 @@
+package org.spongycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PolicyNode;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x509.AccessDescription;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityInformationAccess;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.GeneralSubtree;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.NameConstraints;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.qualified.Iso4217CurrencyCode;
+import org.spongycastle.asn1.x509.qualified.MonetaryValue;
+import org.spongycastle.asn1.x509.qualified.QCStatement;
+import org.spongycastle.i18n.ErrorBundle;
+import org.spongycastle.i18n.LocaleString;
+import org.spongycastle.i18n.filter.TrustedInput;
+import org.spongycastle.i18n.filter.UntrustedInput;
+import org.spongycastle.i18n.filter.UntrustedUrlInput;
+import org.spongycastle.jce.provider.AnnotatedException;
+import org.spongycastle.jce.provider.CertPathValidatorUtilities;
+import org.spongycastle.jce.provider.PKIXNameConstraintValidator;
+import org.spongycastle.jce.provider.PKIXNameConstraintValidatorException;
+import org.spongycastle.jce.provider.PKIXPolicyNode;
+import org.spongycastle.util.Integers;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * PKIXCertPathReviewer<br>
+ * Validation of X.509 Certificate Paths. Tries to find as much errors in the Path as possible.
+ */
+public class PKIXCertPathReviewer extends CertPathValidatorUtilities
+{
+
+ private static final String QC_STATEMENT = X509Extensions.QCStatements.getId();
+ private static final String CRL_DIST_POINTS = X509Extensions.CRLDistributionPoints.getId();
+ private static final String AUTH_INFO_ACCESS = X509Extensions.AuthorityInfoAccess.getId();
+
+ private static final String RESOURCE_NAME = "org.spongycastle.x509.CertPathReviewerMessages";
+
+ // input parameters
+
+ protected CertPath certPath;
+
+ protected PKIXParameters pkixParams;
+
+ protected Date validDate;
+
+ // state variables
+
+ protected List certs;
+
+ protected int n;
+
+ // output variables
+
+ protected List[] notifications;
+ protected List[] errors;
+ protected TrustAnchor trustAnchor;
+ protected PublicKey subjectPublicKey;
+ protected PolicyNode policyTree;
+
+ private boolean initialized;
+
+ /**
+ * Initializes the PKIXCertPathReviewer with the given {@link CertPath} and {@link PKIXParameters} params
+ * @param certPath the {@link CertPath} to validate
+ * @param params the {@link PKIXParameters} to use
+ * @throws CertPathReviewerException if the certPath is empty
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} is already initialized
+ */
+ public void init(CertPath certPath, PKIXParameters params)
+ throws CertPathReviewerException
+ {
+ if (initialized)
+ {
+ throw new IllegalStateException("object is already initialized!");
+ }
+ initialized = true;
+
+ // check input parameters
+ if (certPath == null)
+ {
+ throw new NullPointerException("certPath was null");
+ }
+ this.certPath = certPath;
+
+ certs = certPath.getCertificates();
+ n = certs.size();
+ if (certs.isEmpty())
+ {
+ throw new CertPathReviewerException(
+ new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.emptyCertPath"));
+ }
+
+ pkixParams = (PKIXParameters) params.clone();
+
+ // 6.1.1 - Inputs
+
+ // a) done
+
+ // b)
+
+ validDate = getValidDate(pkixParams);
+
+ // c) part of pkixParams
+
+ // d) done at the beginning of checkSignatures
+
+ // e) f) g) part of pkixParams
+
+ // initialize output parameters
+
+ notifications = null;
+ errors = null;
+ trustAnchor = null;
+ subjectPublicKey = null;
+ policyTree = null;
+ }
+
+ /**
+ * Creates a PKIXCertPathReviewer and initializes it with the given {@link CertPath} and {@link PKIXParameters} params
+ * @param certPath the {@link CertPath} to validate
+ * @param params the {@link PKIXParameters} to use
+ * @throws CertPathReviewerException if the certPath is empty
+ */
+ public PKIXCertPathReviewer(CertPath certPath, PKIXParameters params)
+ throws CertPathReviewerException
+ {
+ init(certPath, params);
+ }
+
+ /**
+ * Creates an empty PKIXCertPathReviewer. Don't forget to call init() to initialize the object.
+ */
+ public PKIXCertPathReviewer()
+ {
+ // do nothing
+ }
+
+ /**
+ *
+ * @return the CertPath that was validated
+ */
+ public CertPath getCertPath()
+ {
+ return certPath;
+ }
+
+ /**
+ *
+ * @return the size of the CertPath
+ */
+ public int getCertPathSize()
+ {
+ return n;
+ }
+
+ /**
+ * Returns an Array of Lists which contains a List of global error messages
+ * and a List of error messages for each certificate in the path.
+ * The global error List is at index 0. The error lists for each certificate at index 1 to n.
+ * The error messages are of type.
+ * @return the Array of Lists which contain the error messages
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public List[] getErrors()
+ {
+ doChecks();
+ return errors;
+ }
+
+ /**
+ * Returns an List of error messages for the certificate at the given index in the CertPath.
+ * If index == -1 then the list of global errors is returned with errors not specific to a certificate.
+ * @param index the index of the certificate in the CertPath
+ * @return List of error messages for the certificate
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public List getErrors(int index)
+ {
+ doChecks();
+ return errors[index + 1];
+ }
+
+ /**
+ * Returns an Array of Lists which contains a List of global notification messages
+ * and a List of botification messages for each certificate in the path.
+ * The global notificatio List is at index 0. The notification lists for each certificate at index 1 to n.
+ * The error messages are of type.
+ * @return the Array of Lists which contain the notification messages
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public List[] getNotifications()
+ {
+ doChecks();
+ return notifications;
+ }
+
+ /**
+ * Returns an List of notification messages for the certificate at the given index in the CertPath.
+ * If index == -1 then the list of global notifications is returned with notifications not specific to a certificate.
+ * @param index the index of the certificate in the CertPath
+ * @return List of notification messages for the certificate
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public List getNotifications(int index)
+ {
+ doChecks();
+ return notifications[index + 1];
+ }
+
+ /**
+ *
+ * @return the valid policy tree, <b>null</b> if no valid policy exists.
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public PolicyNode getPolicyTree()
+ {
+ doChecks();
+ return policyTree;
+ }
+
+ /**
+ *
+ * @return the PublicKey if the last certificate in the CertPath
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public PublicKey getSubjectPublicKey()
+ {
+ doChecks();
+ return subjectPublicKey;
+ }
+
+ /**
+ *
+ * @return the TrustAnchor for the CertPath, <b>null</b> if no valid TrustAnchor was found.
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public TrustAnchor getTrustAnchor()
+ {
+ doChecks();
+ return trustAnchor;
+ }
+
+ /**
+ *
+ * @return if the CertPath is valid
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public boolean isValidCertPath()
+ {
+ doChecks();
+ boolean valid = true;
+ for (int i = 0; i < errors.length; i++)
+ {
+ if (!errors[i].isEmpty())
+ {
+ valid = false;
+ break;
+ }
+ }
+ return valid;
+ }
+
+ protected void addNotification(ErrorBundle msg)
+ {
+ notifications[0].add(msg);
+ }
+
+ protected void addNotification(ErrorBundle msg, int index)
+ {
+ if (index < -1 || index >= n)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ notifications[index + 1].add(msg);
+ }
+
+ protected void addError(ErrorBundle msg)
+ {
+ errors[0].add(msg);
+ }
+
+ protected void addError(ErrorBundle msg, int index)
+ {
+ if (index < -1 || index >= n)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ errors[index + 1].add(msg);
+ }
+
+ protected void doChecks()
+ {
+ if (!initialized)
+ {
+ throw new IllegalStateException("Object not initialized. Call init() first.");
+ }
+ if (notifications == null)
+ {
+ // initialize lists
+ notifications = new List[n+1];
+ errors = new List[n+1];
+
+ for (int i = 0; i < notifications.length; i++)
+ {
+ notifications[i] = new ArrayList();
+ errors[i] = new ArrayList();
+ }
+
+ // check Signatures
+ checkSignatures();
+
+ // check Name Constraints
+ checkNameConstraints();
+
+ // check Path Length
+ checkPathLength();
+
+ // check Policy
+ checkPolicy();
+
+ // check other critical extensions
+ checkCriticalExtensions();
+
+ }
+ }
+
+ private void checkNameConstraints()
+ {
+ X509Certificate cert = null;
+
+ //
+ // Setup
+ //
+
+ // (b) and (c)
+ PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
+
+ //
+ // process each certificate except the last in the path
+ //
+ int index;
+ int i;
+
+ try
+ {
+ for (index = certs.size()-1; index>0; index--)
+ {
+ i = n - index;
+
+ //
+ // certificate processing
+ //
+
+ cert = (X509Certificate) certs.get(index);
+
+ // b),c)
+
+ if (!isSelfIssued(cert))
+ {
+ X500Principal principal = getSubjectPrincipal(cert);
+ ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(principal.getEncoded()));
+ ASN1Sequence dns;
+
+ try
+ {
+ dns = (ASN1Sequence)aIn.readObject();
+ }
+ catch (IOException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ncSubjectNameError",
+ new Object[] {new UntrustedInput(principal)});
+ throw new CertPathReviewerException(msg,e,certPath,index);
+ }
+
+ try
+ {
+ nameConstraintValidator.checkPermittedDN(dns);
+ }
+ catch (PKIXNameConstraintValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedDN",
+ new Object[] {new UntrustedInput(principal.getName())});
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+
+ try
+ {
+ nameConstraintValidator.checkExcludedDN(dns);
+ }
+ catch (PKIXNameConstraintValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedDN",
+ new Object[] {new UntrustedInput(principal.getName())});
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+
+ ASN1Sequence altName;
+ try
+ {
+ altName = (ASN1Sequence)getExtensionValue(cert, SUBJECT_ALTERNATIVE_NAME);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.subjAltNameExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+
+ if (altName != null)
+ {
+ for (int j = 0; j < altName.size(); j++)
+ {
+ GeneralName name = GeneralName.getInstance(altName.getObjectAt(j));
+
+ try
+ {
+ nameConstraintValidator.checkPermitted(name);
+ nameConstraintValidator.checkExcluded(name);
+ }
+ catch (PKIXNameConstraintValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedEmail",
+ new Object[] {new UntrustedInput(name)});
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+// switch(o.getTagNo()) TODO - move resources to PKIXNameConstraints
+// {
+// case 1:
+// String email = DERIA5String.getInstance(o, true).getString();
+//
+// try
+// {
+// checkPermittedEmail(permittedSubtreesEmail, email);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedEmail",
+// new Object[] {new UntrustedInput(email)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// try
+// {
+// checkExcludedEmail(excludedSubtreesEmail, email);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedEmail",
+// new Object[] {new UntrustedInput(email)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// break;
+// case 4:
+// ASN1Sequence altDN = ASN1Sequence.getInstance(o, true);
+//
+// try
+// {
+// checkPermittedDN(permittedSubtreesDN, altDN);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// X509Name altDNName = new X509Name(altDN);
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedDN",
+// new Object[] {new UntrustedInput(altDNName)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// try
+// {
+// checkExcludedDN(excludedSubtreesDN, altDN);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// X509Name altDNName = new X509Name(altDN);
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedDN",
+// new Object[] {new UntrustedInput(altDNName)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// break;
+// case 7:
+// byte[] ip = ASN1OctetString.getInstance(o, true).getOctets();
+//
+// try
+// {
+// checkPermittedIP(permittedSubtreesIP, ip);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedIP",
+// new Object[] {IPtoString(ip)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// try
+// {
+// checkExcludedIP(excludedSubtreesIP, ip);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedIP",
+// new Object[] {IPtoString(ip)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+// }
+ }
+ }
+ }
+
+ //
+ // prepare for next certificate
+ //
+
+ //
+ // (g) handle the name constraints extension
+ //
+ ASN1Sequence ncSeq;
+ try
+ {
+ ncSeq = (ASN1Sequence)getExtensionValue(cert, NAME_CONSTRAINTS);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ncExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+
+ if (ncSeq != null)
+ {
+ NameConstraints nc = NameConstraints.getInstance(ncSeq);
+
+ //
+ // (g) (1) permitted subtrees
+ //
+ GeneralSubtree[] permitted = nc.getPermittedSubtrees();
+ if (permitted != null)
+ {
+ nameConstraintValidator.intersectPermittedSubtree(permitted);
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ GeneralSubtree[] excluded = nc.getExcludedSubtrees();
+ if (excluded != null)
+ {
+ for (int c = 0; c != excluded.length; c++)
+ {
+ nameConstraintValidator.addExcludedSubtree(excluded[c]);
+ }
+ }
+ }
+
+ } // for
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage(),cpre.getIndex());
+ }
+
+ }
+
+ /*
+ * checks: - path length constraints and reports - total path length
+ */
+ private void checkPathLength()
+ {
+ // init
+ int maxPathLength = n;
+ int totalPathLength = 0;
+
+ X509Certificate cert = null;
+
+ int i;
+ for (int index = certs.size() - 1; index > 0; index--)
+ {
+ i = n - index;
+
+ cert = (X509Certificate) certs.get(index);
+
+ // l)
+
+ if (!isSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.pathLenghtExtended");
+ addError(msg);
+ }
+ maxPathLength--;
+ totalPathLength++;
+ }
+
+ // m)
+
+ BasicConstraints bc;
+ try
+ {
+ bc = BasicConstraints.getInstance(getExtensionValue(cert,
+ BASIC_CONSTRAINTS));
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.processLengthConstError");
+ addError(msg,index);
+ bc = null;
+ }
+
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.intValue();
+
+ if (_plc < maxPathLength)
+ {
+ maxPathLength = _plc;
+ }
+ }
+ }
+
+ }
+
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.totalPathLength",
+ new Object[]{Integers.valueOf(totalPathLength)});
+
+ addNotification(msg);
+ }
+
+ /*
+ * checks: - signatures - name chaining - validity of certificates - todo:
+ * if certificate revoked (if specified in the parameters)
+ */
+ private void checkSignatures()
+ {
+ // 1.6.1 - Inputs
+
+ // d)
+
+ TrustAnchor trust = null;
+ X500Principal trustPrincipal = null;
+
+ // validation date
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certPathValidDate",
+ new Object[] {new TrustedInput(validDate), new TrustedInput(new Date())});
+ addNotification(msg);
+ }
+
+ // find trust anchors
+ try
+ {
+ X509Certificate cert = (X509Certificate) certs.get(certs.size() - 1);
+ Collection trustColl = getTrustAnchors(cert,pkixParams.getTrustAnchors());
+ if (trustColl.size() > 1)
+ {
+ // conflicting trust anchors
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.conflictingTrustAnchors",
+ new Object[]{Integers.valueOf(trustColl.size()),
+ new UntrustedInput(cert.getIssuerX500Principal())});
+ addError(msg);
+ }
+ else if (trustColl.isEmpty())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.noTrustAnchorFound",
+ new Object[]{new UntrustedInput(cert.getIssuerX500Principal()),
+ Integers.valueOf(pkixParams.getTrustAnchors().size())});
+ addError(msg);
+ }
+ else
+ {
+ PublicKey trustPublicKey;
+ trust = (TrustAnchor) trustColl.iterator().next();
+ if (trust.getTrustedCert() != null)
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ try
+ {
+ CertPathValidatorUtilities.verifyX509Certificate(cert, trustPublicKey,
+ pkixParams.getSigProvider());
+ }
+ catch (SignatureException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustButInvalidCert");
+ addError(msg);
+ }
+ catch (Exception e)
+ {
+ // do nothing, error occurs again later
+ }
+ }
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage());
+ }
+ catch (Throwable t)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.unknown",
+ new Object[] {new UntrustedInput(t.getMessage()), new UntrustedInput(t)});
+ addError(msg);
+ }
+
+ if (trust != null)
+ {
+ // get the name of the trustAnchor
+ X509Certificate sign = trust.getTrustedCert();
+ try
+ {
+ if (sign != null)
+ {
+ trustPrincipal = getSubjectPrincipal(sign);
+ }
+ else
+ {
+ trustPrincipal = new X500Principal(trust.getCAName());
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustDNInvalid",
+ new Object[] {new UntrustedInput(trust.getCAName())});
+ addError(msg);
+ }
+
+ // test key usages of the trust anchor
+ if (sign != null)
+ {
+ boolean[] ku = sign.getKeyUsage();
+ if (ku != null && !ku[5])
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.trustKeyUsage");
+ addNotification(msg);
+ }
+ }
+ }
+
+ // 1.6.2 - Initialization
+
+ PublicKey workingPublicKey = null;
+ X500Principal workingIssuerName = trustPrincipal;
+
+ X509Certificate sign = null;
+
+ AlgorithmIdentifier workingAlgId = null;
+ DERObjectIdentifier workingPublicKeyAlgorithm = null;
+ ASN1Encodable workingPublicKeyParameters = null;
+
+ if (trust != null)
+ {
+ sign = trust.getTrustedCert();
+
+ if (sign != null)
+ {
+ workingPublicKey = sign.getPublicKey();
+ }
+ else
+ {
+ workingPublicKey = trust.getCAPublicKey();
+ }
+
+ try
+ {
+ workingAlgId = getAlgorithmIdentifier(workingPublicKey);
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ catch (CertPathValidatorException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustPubKeyError");
+ addError(msg);
+ workingAlgId = null;
+ }
+
+ }
+
+ // Basic cert checks
+
+ X509Certificate cert = null;
+ int i;
+
+ for (int index = certs.size() - 1; index >= 0; index--)
+ {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialied the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate) certs.get(index);
+
+ // verify signature
+ if (workingPublicKey != null)
+ {
+ try
+ {
+ CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
+ pkixParams.getSigProvider());
+ }
+ catch (GeneralSecurityException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.signatureNotVerified",
+ new Object[] {ex.getMessage(),ex,ex.getClass().getName()});
+ addError(msg,index);
+ }
+ }
+ else if (isSelfIssued(cert))
+ {
+ try
+ {
+ CertPathValidatorUtilities.verifyX509Certificate(cert, cert.getPublicKey(),
+ pkixParams.getSigProvider());
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.rootKeyIsValidButNotATrustAnchor");
+ addError(msg, index);
+ }
+ catch (GeneralSecurityException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.signatureNotVerified",
+ new Object[] {ex.getMessage(),ex,ex.getClass().getName()});
+ addError(msg,index);
+ }
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.NoIssuerPublicKey");
+ // if there is an authority key extension add the serial and issuer of the missing certificate
+ byte[] akiBytes = cert.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+ if (akiBytes != null)
+ {
+ try
+ {
+ AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance(
+ X509ExtensionUtil.fromExtensionValue(akiBytes));
+ GeneralNames issuerNames = aki.getAuthorityCertIssuer();
+ if (issuerNames != null)
+ {
+ GeneralName name = issuerNames.getNames()[0];
+ BigInteger serial = aki.getAuthorityCertSerialNumber();
+ if (serial != null)
+ {
+ Object[] extraArgs = {new LocaleString(RESOURCE_NAME, "missingIssuer"), " \"", name ,
+ "\" ", new LocaleString(RESOURCE_NAME, "missingSerial") , " ", serial};
+ msg.setExtraArguments(extraArgs);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ addError(msg,index);
+ }
+
+ // certificate valid?
+ try
+ {
+ cert.checkValidity(validDate);
+ }
+ catch (CertificateNotYetValidException cnve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certificateNotYetValid",
+ new Object[] {new TrustedInput(cert.getNotBefore())});
+ addError(msg,index);
+ }
+ catch (CertificateExpiredException cee)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certificateExpired",
+ new Object[] {new TrustedInput(cert.getNotAfter())});
+ addError(msg,index);
+ }
+
+ // certificate revoked?
+ if (pkixParams.isRevocationEnabled())
+ {
+ // read crl distribution points extension
+ CRLDistPoint crlDistPoints = null;
+ try
+ {
+ ASN1Primitive crl_dp = getExtensionValue(cert,CRL_DIST_POINTS);
+ if (crl_dp != null)
+ {
+ crlDistPoints = CRLDistPoint.getInstance(crl_dp);
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlDistPtExtError");
+ addError(msg,index);
+ }
+
+ // read authority information access extension
+ AuthorityInformationAccess authInfoAcc = null;
+ try
+ {
+ ASN1Primitive auth_info_acc = getExtensionValue(cert,AUTH_INFO_ACCESS);
+ if (auth_info_acc != null)
+ {
+ authInfoAcc = AuthorityInformationAccess.getInstance(auth_info_acc);
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlAuthInfoAccError");
+ addError(msg,index);
+ }
+
+ Vector crlDistPointUrls = getCRLDistUrls(crlDistPoints);
+ Vector ocspUrls = getOCSPUrls(authInfoAcc);
+
+ // add notifications with the crl distribution points
+
+ // output crl distribution points
+ Iterator urlIt = crlDistPointUrls.iterator();
+ while (urlIt.hasNext())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlDistPoint",
+ new Object[] {new UntrustedUrlInput(urlIt.next())});
+ addNotification(msg,index);
+ }
+
+ // output ocsp urls
+ urlIt = ocspUrls.iterator();
+ while (urlIt.hasNext())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ocspLocation",
+ new Object[] {new UntrustedUrlInput(urlIt.next())});
+ addNotification(msg,index);
+ }
+
+ // TODO also support Netscapes revocation-url and/or OCSP instead of CRLs for revocation checking
+ // check CRLs
+ try
+ {
+ checkRevocation(pkixParams, cert, validDate, sign, workingPublicKey, crlDistPointUrls, ocspUrls, index);
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage(),index);
+ }
+ }
+
+ // certificate issuer correct
+ if (workingIssuerName != null && !cert.getIssuerX500Principal().equals(workingIssuerName))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certWrongIssuer",
+ new Object[] {workingIssuerName.getName(),
+ cert.getIssuerX500Principal().getName()});
+ addError(msg,index);
+ }
+
+ //
+ // prepare for next certificate
+ //
+ if (i != n)
+ {
+
+ if (cert != null && cert.getVersion() == 1)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCACert");
+ addError(msg,index);
+ }
+
+ // k)
+
+ BasicConstraints bc;
+ try
+ {
+ bc = BasicConstraints.getInstance(getExtensionValue(cert,
+ BASIC_CONSTRAINTS));
+ if (bc != null)
+ {
+ if (!bc.isCA())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCACert");
+ addError(msg,index);
+ }
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noBasicConstraints");
+ addError(msg,index);
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.errorProcesingBC");
+ addError(msg,index);
+ }
+
+ // n)
+
+ boolean[] _usage = cert.getKeyUsage();
+
+ if ((_usage != null) && !_usage[KEY_CERT_SIGN])
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCertSign");
+ addError(msg,index);
+ }
+
+ } // if
+
+ // set signing certificate for next round
+ sign = cert;
+
+ // c)
+
+ workingIssuerName = cert.getSubjectX500Principal();
+
+ // d) e) f)
+
+ try
+ {
+ workingPublicKey = getNextWorkingKey(certs, index);
+ workingAlgId = getAlgorithmIdentifier(workingPublicKey);
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ catch (CertPathValidatorException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.pubKeyError");
+ addError(msg,index);
+ workingAlgId = null;
+ workingPublicKeyAlgorithm = null;
+ workingPublicKeyParameters = null;
+ }
+
+ } // for
+
+ trustAnchor = trust;
+ subjectPublicKey = workingPublicKey;
+ }
+
+ private void checkPolicy()
+ {
+ //
+ // 6.1.1 Inputs
+ //
+
+ // c) Initial Policy Set
+
+ Set userInitialPolicySet = pkixParams.getInitialPolicies();
+
+ // e) f) g) are part of pkixParams
+
+ //
+ // 6.1.2 Initialization
+ //
+
+ // a) valid policy tree
+
+ List[] policyNodes = new ArrayList[n + 1];
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ Set policySet = new HashSet();
+
+ policySet.add(ANY_POLICY);
+
+ PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0,
+ policySet, null, new HashSet(), ANY_POLICY, false);
+
+ policyNodes[0].add(validPolicyTree);
+
+ // d) explicit policy
+
+ int explicitPolicy;
+ if (pkixParams.isExplicitPolicyRequired())
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ // e) inhibit any policy
+
+ int inhibitAnyPolicy;
+ if (pkixParams.isAnyPolicyInhibited())
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ // f) policy mapping
+
+ int policyMapping;
+ if (pkixParams.isPolicyMappingInhibited())
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ Set acceptablePolicies = null;
+
+ //
+ // 6.1.3 Basic Certificate processing
+ //
+
+ X509Certificate cert = null;
+ int index;
+ int i;
+
+ try
+ {
+ for (index = certs.size() - 1; index >= 0; index--)
+ {
+ // i as defined in the algorithm description
+ i = n - index;
+
+ // set certificate to be checked in this round
+ cert = (X509Certificate) certs.get(index);
+
+ // d) process policy information
+
+ ASN1Sequence certPolicies;
+ try
+ {
+ certPolicies = (ASN1Sequence) getExtensionValue(
+ cert, CERTIFICATE_POLICIES);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+ if (certPolicies != null && validPolicyTree != null)
+ {
+
+ // d) 1)
+
+ Enumeration e = certPolicies.getObjects();
+ Set pols = new HashSet();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+ DERObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+ pols.add(pOid.getId());
+
+ if (!ANY_POLICY.equals(pOid.getId()))
+ {
+ Set pq;
+ try
+ {
+ pq = getQualifierSet(pInfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+
+ boolean match = processCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ processCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies == null || acceptablePolicies.contains(ANY_POLICY))
+ {
+ acceptablePolicies = pols;
+ }
+ else
+ {
+ Iterator it = acceptablePolicies.iterator();
+ Set t1 = new HashSet();
+
+ while (it.hasNext())
+ {
+ Object o = it.next();
+
+ if (pols.contains(o))
+ {
+ t1.add(o);
+ }
+ }
+
+ acceptablePolicies = t1;
+ }
+
+ // d) 2)
+
+ if ((inhibitAnyPolicy > 0) || ((i < n) && isSelfIssued(cert)))
+ {
+ e = certPolicies.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+ if (ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+ {
+ Set _apq;
+ try
+ {
+ _apq = getQualifierSet(pInfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+ List _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode) _nodes.get(k);
+
+ Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+ while (_policySetIter.hasNext())
+ {
+ Object _tmp = _policySetIter.next();
+
+ String _policy;
+ if (_tmp instanceof String)
+ {
+ _policy = (String) _tmp;
+ }
+ else if (_tmp instanceof DERObjectIdentifier)
+ {
+ _policy = ((DERObjectIdentifier) _tmp).getId();
+ }
+ else
+ {
+ continue;
+ }
+
+ boolean _found = false;
+ Iterator _childrenIter = _node
+ .getChildren();
+
+ while (_childrenIter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode) _childrenIter.next();
+
+ if (_policy.equals(_child.getValidPolicy()))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ Set _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.add(_policy);
+
+ PKIXPolicyNode _newChild = new PKIXPolicyNode(
+ new ArrayList(), i,
+ _newChildExpectedPolicies,
+ _node, _apq, _policy, false);
+ _node.addChild(_newChild);
+ policyNodes[i].add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode) nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(
+ validPolicyTree, policyNodes, node);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensionOids != null)
+ {
+ boolean critical = criticalExtensionOids.contains(CERTIFICATE_POLICIES);
+
+ List nodes = policyNodes[i];
+ for (int j = 0; j < nodes.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode) nodes.get(j);
+ node.setCritical(critical);
+ }
+ }
+
+ }
+
+ // e)
+
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+
+ // f)
+
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noValidPolicyTree");
+ throw new CertPathReviewerException(msg);
+ }
+
+ //
+ // 6.1.4 preparation for next Certificate
+ //
+
+ if (i != n)
+ {
+
+ // a)
+
+ ASN1Primitive pm;
+ try
+ {
+ pm = getExtensionValue(cert, POLICY_MAPPINGS);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyMapExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence) pm;
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence) mappings.getObjectAt(j);
+ DERObjectIdentifier ip_id = (DERObjectIdentifier) mapping.getObjectAt(0);
+ DERObjectIdentifier sp_id = (DERObjectIdentifier) mapping.getObjectAt(1);
+ if (ANY_POLICY.equals(ip_id.getId()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicyMapping");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ if (ANY_POLICY.equals(sp_id.getId()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicyMapping");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ }
+ }
+
+ // b)
+
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence)pm;
+ Map m_idp = new HashMap();
+ Set s_idp = new HashSet();
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+ String id_p = ((DERObjectIdentifier)mapping.getObjectAt(0)).getId();
+ String sd_p = ((DERObjectIdentifier)mapping.getObjectAt(1)).getId();
+ Set tmp;
+
+ if (!m_idp.containsKey(id_p))
+ {
+ tmp = new HashSet();
+ tmp.add(sd_p);
+ m_idp.put(id_p, tmp);
+ s_idp.add(id_p);
+ }
+ else
+ {
+ tmp = (Set)m_idp.get(id_p);
+ tmp.add(sd_p);
+ }
+ }
+
+ Iterator it_idp = s_idp.iterator();
+ while (it_idp.hasNext())
+ {
+ String id_p = (String)it_idp.next();
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ try
+ {
+ prepareNextCertB1(i,policyNodes,id_p,m_idp,cert);
+ }
+ catch (AnnotatedException ae)
+ {
+ // error processing certificate policies extension
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ // error building qualifier set
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ validPolicyTree = prepareNextCertB2(i,policyNodes,id_p,validPolicyTree);
+ }
+
+ }
+ }
+
+ //
+ // h)
+ //
+
+ if (!isSelfIssued(cert))
+ {
+
+ // (1)
+ if (explicitPolicy != 0)
+ {
+ explicitPolicy--;
+ }
+
+ // (2)
+ if (policyMapping != 0)
+ {
+ policyMapping--;
+ }
+
+ // (3)
+ if (inhibitAnyPolicy != 0)
+ {
+ inhibitAnyPolicy--;
+ }
+
+ }
+
+ //
+ // i)
+ //
+
+ try
+ {
+ ASN1Sequence pc = (ASN1Sequence) getExtensionValue(cert,POLICY_CONSTRAINTS);
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject) policyConstraints.nextElement();
+ int tmpInt;
+
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < explicitPolicy)
+ {
+ explicitPolicy = tmpInt;
+ }
+ break;
+ case 1:
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < policyMapping)
+ {
+ policyMapping = tmpInt;
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyConstExtError");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+
+ //
+ // j)
+ //
+
+ try
+ {
+ DERInteger iap = (DERInteger)getExtensionValue(cert, INHIBIT_ANY_POLICY);
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.getValue().intValue();
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ {
+ inhibitAnyPolicy = _inhibitAnyPolicy;
+ }
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyInhibitExtError");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ }
+
+ }
+
+ //
+ // 6.1.5 Wrap up
+ //
+
+ //
+ // a)
+ //
+
+ if (!isSelfIssued(cert) && explicitPolicy > 0)
+ {
+ explicitPolicy--;
+ }
+
+ //
+ // b)
+ //
+
+ try
+ {
+ ASN1Sequence pc = (ASN1Sequence) getExtensionValue(cert, POLICY_CONSTRAINTS);
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ int tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt == 0)
+ {
+ explicitPolicy = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (AnnotatedException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyConstExtError");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+
+
+ //
+ // (g)
+ //
+ PKIXPolicyNode intersection;
+
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (pkixParams.isExplicitPolicyRequired())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.explicitPolicy");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ intersection = null;
+ }
+ else if (isAnyPolicy(userInitialPolicySet)) // (g) (ii)
+ {
+ if (pkixParams.isExplicitPolicyRequired())
+ {
+ if (acceptablePolicies.isEmpty())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.explicitPolicy");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ else
+ {
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ _validPolicyNodeSet.add(_iter.next());
+ }
+ }
+ }
+ }
+
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!acceptablePolicies.contains(_validPolicy))
+ {
+ //validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in RFC3280.
+ // However, as far as the validation result is concerned, both produce
+ // adequate result. The only difference is whether AnyPolicy is remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+ if (!ANY_POLICY.equals(_c_node.getValidPolicy()))
+ {
+ _validPolicyNodeSet.add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!userInitialPolicySet.contains(_validPolicy))
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+
+ if ((explicitPolicy <= 0) && (intersection == null))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicy");
+ throw new CertPathReviewerException(msg);
+ }
+
+ validPolicyTree = intersection;
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage(),cpre.getIndex());
+ validPolicyTree = null;
+ }
+ }
+
+ private void checkCriticalExtensions()
+ {
+ //
+ // initialise CertPathChecker's
+ //
+ List pathCheckers = pkixParams.getCertPathCheckers();
+ Iterator certIter = pathCheckers.iterator();
+
+ try
+ {
+ try
+ {
+ while (certIter.hasNext())
+ {
+ ((PKIXCertPathChecker)certIter.next()).init(false);
+ }
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certPathCheckerError",
+ new Object[] {cpve.getMessage(),cpve,cpve.getClass().getName()});
+ throw new CertPathReviewerException(msg,cpve);
+ }
+
+ //
+ // process critical extesions for each certificate
+ //
+
+ X509Certificate cert = null;
+
+ int index;
+
+ for (index = certs.size()-1; index >= 0; index--)
+ {
+ cert = (X509Certificate) certs.get(index);
+
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+ if (criticalExtensions == null || criticalExtensions.isEmpty())
+ {
+ continue;
+ }
+ // remove already processed extensions
+ criticalExtensions.remove(KEY_USAGE);
+ criticalExtensions.remove(CERTIFICATE_POLICIES);
+ criticalExtensions.remove(POLICY_MAPPINGS);
+ criticalExtensions.remove(INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(POLICY_CONSTRAINTS);
+ criticalExtensions.remove(BASIC_CONSTRAINTS);
+ criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(NAME_CONSTRAINTS);
+
+ // process qcStatements extension
+ if (criticalExtensions.contains(QC_STATEMENT))
+ {
+ if (processQcStatements(cert,index))
+ {
+ criticalExtensions.remove(QC_STATEMENT);
+ }
+ }
+
+ Iterator tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.criticalExtensionError",
+ new Object[] {e.getMessage(),e,e.getClass().getName()});
+ throw new CertPathReviewerException(msg,e.getCause(),certPath,index);
+ }
+ }
+ if (!criticalExtensions.isEmpty())
+ {
+ ErrorBundle msg;
+ Iterator it = criticalExtensions.iterator();
+ while (it.hasNext())
+ {
+ msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.unknownCriticalExt",
+ new Object[] {new DERObjectIdentifier((String) it.next())});
+ addError(msg, index);
+ }
+ }
+ }
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage(),cpre.getIndex());
+ }
+ }
+
+ private boolean processQcStatements(
+ X509Certificate cert,
+ int index)
+ {
+ try
+ {
+ boolean unknownStatement = false;
+
+ ASN1Sequence qcSt = (ASN1Sequence) getExtensionValue(cert,QC_STATEMENT);
+ for (int j = 0; j < qcSt.size(); j++)
+ {
+ QCStatement stmt = QCStatement.getInstance(qcSt.getObjectAt(j));
+ if (QCStatement.id_etsi_qcs_QcCompliance.equals(stmt.getStatementId()))
+ {
+ // process statement - just write a notification that the certificate contains this statement
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcEuCompliance");
+ addNotification(msg,index);
+ }
+ else if (QCStatement.id_qcs_pkixQCSyntax_v1.equals(stmt.getStatementId()))
+ {
+ // process statement - just recognize the statement
+ }
+ else if (QCStatement.id_etsi_qcs_QcSSCD.equals(stmt.getStatementId()))
+ {
+ // process statement - just write a notification that the certificate contains this statement
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcSSCD");
+ addNotification(msg,index);
+ }
+ else if (QCStatement.id_etsi_qcs_LimiteValue.equals(stmt.getStatementId()))
+ {
+ // process statement - write a notification containing the limit value
+ MonetaryValue limit = MonetaryValue.getInstance(stmt.getStatementInfo());
+ Iso4217CurrencyCode currency = limit.getCurrency();
+ double value = limit.getAmount().doubleValue() * Math.pow(10,limit.getExponent().doubleValue());
+ ErrorBundle msg;
+ if (limit.getCurrency().isAlphabetic())
+ {
+ msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueAlpha",
+ new Object[] {limit.getCurrency().getAlphabetic(),
+ new TrustedInput(new Double(value)),
+ limit});
+ }
+ else
+ {
+ msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueNum",
+ new Object[]{Integers.valueOf(limit.getCurrency().getNumeric()),
+ new TrustedInput(new Double(value)),
+ limit});
+ }
+ addNotification(msg,index);
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcUnknownStatement",
+ new Object[] {stmt.getStatementId(),new UntrustedInput(stmt)});
+ addNotification(msg,index);
+ unknownStatement = true;
+ }
+ }
+
+ return !unknownStatement;
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcStatementExtError");
+ addError(msg,index);
+ }
+
+ return false;
+ }
+
+ private String IPtoString(byte[] ip)
+ {
+ String result;
+ try
+ {
+ result = InetAddress.getByAddress(ip).getHostAddress();
+ }
+ catch (Exception e)
+ {
+ StringBuffer b = new StringBuffer();
+
+ for (int i = 0; i != ip.length; i++)
+ {
+ b.append(Integer.toHexString(ip[i] & 0xff));
+ b.append(' ');
+ }
+
+ result = b.toString();
+ }
+
+ return result;
+ }
+
+ protected void checkRevocation(PKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate sign,
+ PublicKey workingPublicKey,
+ Vector crlDistPointUrls,
+ Vector ocspUrls,
+ int index)
+ throws CertPathReviewerException
+ {
+ checkCRLs(paramsPKIX, cert, validDate, sign, workingPublicKey, crlDistPointUrls, index);
+ }
+
+ protected void checkCRLs(
+ PKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate sign,
+ PublicKey workingPublicKey,
+ Vector crlDistPointUrls,
+ int index)
+ throws CertPathReviewerException
+ {
+ X509CRLStoreSelector crlselect;
+ crlselect = new X509CRLStoreSelector();
+
+ try
+ {
+ crlselect.addIssuerName(getEncodedIssuerPrincipal(cert).getEncoded());
+ }
+ catch (IOException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlIssuerException");
+ throw new CertPathReviewerException(msg,e);
+ }
+
+ crlselect.setCertificateChecking(cert);
+
+ Iterator crl_iter;
+ try
+ {
+ Collection crl_coll = CRL_UTIL.findCRLs(crlselect, paramsPKIX);
+ crl_iter = crl_coll.iterator();
+
+ if (crl_coll.isEmpty())
+ {
+ // notifcation - no local crls found
+ crl_coll = CRL_UTIL.findCRLs(new X509CRLStoreSelector(),paramsPKIX);
+ Iterator it = crl_coll.iterator();
+ List nonMatchingCrlNames = new ArrayList();
+ while (it.hasNext())
+ {
+ nonMatchingCrlNames.add(((X509CRL) it.next()).getIssuerX500Principal());
+ }
+ int numbOfCrls = nonMatchingCrlNames.size();
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.noCrlInCertstore",
+ new Object[]{new UntrustedInput(crlselect.getIssuerNames()),
+ new UntrustedInput(nonMatchingCrlNames),
+ Integers.valueOf(numbOfCrls)});
+ addNotification(msg,index);
+ }
+
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlExtractionError",
+ new Object[] {ae.getCause().getMessage(),ae.getCause(),ae.getCause().getClass().getName()});
+ addError(msg,index);
+ crl_iter = new ArrayList().iterator();
+ }
+ boolean validCrlFound = false;
+ X509CRL crl = null;
+ while (crl_iter.hasNext())
+ {
+ crl = (X509CRL)crl_iter.next();
+
+ if (crl.getNextUpdate() == null
+ || paramsPKIX.getDate().before(crl.getNextUpdate()))
+ {
+ validCrlFound = true;
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.localValidCRL",
+ new Object[] {new TrustedInput(crl.getThisUpdate()), new TrustedInput(crl.getNextUpdate())});
+ addNotification(msg,index);
+ break;
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.localInvalidCRL",
+ new Object[] {new TrustedInput(crl.getThisUpdate()), new TrustedInput(crl.getNextUpdate())});
+ addNotification(msg,index);
+ }
+ }
+
+ // if no valid crl was found in the CertStores try to get one from a
+ // crl distribution point
+ if (!validCrlFound)
+ {
+ X509CRL onlineCRL = null;
+ Iterator urlIt = crlDistPointUrls.iterator();
+ while (urlIt.hasNext())
+ {
+ try
+ {
+ String location = (String) urlIt.next();
+ onlineCRL = getCRL(location);
+ if (onlineCRL != null)
+ {
+ // check if crl issuer is correct
+ if (!cert.getIssuerX500Principal().equals(onlineCRL.getIssuerX500Principal()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.onlineCRLWrongCA",
+ new Object[] {new UntrustedInput(onlineCRL.getIssuerX500Principal().getName()),
+ new UntrustedInput(cert.getIssuerX500Principal().getName()),
+ new UntrustedUrlInput(location)});
+ addNotification(msg,index);
+ continue;
+ }
+
+ if (onlineCRL.getNextUpdate() == null
+ || pkixParams.getDate().before(onlineCRL.getNextUpdate()))
+ {
+ validCrlFound = true;
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.onlineValidCRL",
+ new Object[] {new TrustedInput(onlineCRL.getThisUpdate()),
+ new TrustedInput(onlineCRL.getNextUpdate()),
+ new UntrustedUrlInput(location)});
+ addNotification(msg,index);
+ crl = onlineCRL;
+ break;
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.onlineInvalidCRL",
+ new Object[] {new TrustedInput(onlineCRL.getThisUpdate()),
+ new TrustedInput(onlineCRL.getNextUpdate()),
+ new UntrustedUrlInput(location)});
+ addNotification(msg,index);
+ }
+ }
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addNotification(cpre.getErrorMessage(),index);
+ }
+ }
+ }
+
+ // check the crl
+ X509CRLEntry crl_entry;
+ if (crl != null)
+ {
+ if (sign != null)
+ {
+ boolean[] keyusage = sign.getKeyUsage();
+
+ if (keyusage != null
+ && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCrlSigningPermited");
+ throw new CertPathReviewerException(msg);
+ }
+ }
+
+ if (workingPublicKey != null)
+ {
+ try
+ {
+ crl.verify(workingPublicKey, "SC");
+ }
+ catch (Exception e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlVerifyFailed");
+ throw new CertPathReviewerException(msg,e);
+ }
+ }
+ else // issuer public key not known
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlNoIssuerPublicKey");
+ throw new CertPathReviewerException(msg);
+ }
+
+ crl_entry = crl.getRevokedCertificate(cert.getSerialNumber());
+ if (crl_entry != null)
+ {
+ String reason = null;
+
+ if (crl_entry.hasExtensions())
+ {
+ DEREnumerated reasonCode;
+ try
+ {
+ reasonCode = DEREnumerated.getInstance(getExtensionValue(crl_entry, X509Extensions.ReasonCode.getId()));
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlReasonExtError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+ if (reasonCode != null)
+ {
+ reason = crlReasons[reasonCode.getValue().intValue()];
+ }
+ }
+
+ if (reason == null)
+ {
+ reason = crlReasons[7]; // unknown
+ }
+
+ // i18n reason
+ LocaleString ls = new LocaleString(RESOURCE_NAME, reason);
+
+ if (!validDate.before(crl_entry.getRevocationDate()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certRevoked",
+ new Object[] {new TrustedInput(crl_entry.getRevocationDate()),ls});
+ throw new CertPathReviewerException(msg);
+ }
+ else // cert was revoked after validation date
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.revokedAfterValidation",
+ new Object[] {new TrustedInput(crl_entry.getRevocationDate()),ls});
+ addNotification(msg,index);
+ }
+ }
+ else // cert is not revoked
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notRevoked");
+ addNotification(msg,index);
+ }
+
+ //
+ // warn if a new crl is available
+ //
+ if (crl.getNextUpdate() != null && crl.getNextUpdate().before(pkixParams.getDate()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlUpdateAvailable",
+ new Object[] {new TrustedInput(crl.getNextUpdate())});
+ addNotification(msg,index);
+ }
+
+ //
+ // check the DeltaCRL indicator, base point and the issuing distribution point
+ //
+ ASN1Primitive idp;
+ try
+ {
+ idp = getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.distrPtExtError");
+ throw new CertPathReviewerException(msg);
+ }
+ ASN1Primitive dci;
+ try
+ {
+ dci = getExtensionValue(crl, DELTA_CRL_INDICATOR);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.deltaCrlExtError");
+ throw new CertPathReviewerException(msg);
+ }
+
+ if (dci != null)
+ {
+ X509CRLStoreSelector baseSelect = new X509CRLStoreSelector();
+
+ try
+ {
+ baseSelect.addIssuerName(getIssuerPrincipal(crl).getEncoded());
+ }
+ catch (IOException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlIssuerException");
+ throw new CertPathReviewerException(msg,e);
+ }
+
+ baseSelect.setMinCRLNumber(((DERInteger)dci).getPositiveValue());
+ try
+ {
+ baseSelect.setMaxCRLNumber(((DERInteger)getExtensionValue(crl, CRL_NUMBER)).getPositiveValue().subtract(BigInteger.valueOf(1)));
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlNbrExtError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+
+ boolean foundBase = false;
+ Iterator it;
+ try
+ {
+ it = CRL_UTIL.findCRLs(baseSelect, paramsPKIX).iterator();
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlExtractionError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+ while (it.hasNext())
+ {
+ X509CRL base = (X509CRL)it.next();
+
+ ASN1Primitive baseIdp;
+ try
+ {
+ baseIdp = getExtensionValue(base, ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.distrPtExtError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+
+ if (idp == null)
+ {
+ if (baseIdp == null)
+ {
+ foundBase = true;
+ break;
+ }
+ }
+ else
+ {
+ if (idp.equals(baseIdp))
+ {
+ foundBase = true;
+ break;
+ }
+ }
+ }
+
+ if (!foundBase)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noBaseCRL");
+ throw new CertPathReviewerException(msg);
+ }
+ }
+
+ if (idp != null)
+ {
+ IssuingDistributionPoint p = IssuingDistributionPoint.getInstance(idp);
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(getExtensionValue(cert, BASIC_CONSTRAINTS));
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlBCExtError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+
+ if (p.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyUserCert");
+ throw new CertPathReviewerException(msg);
+ }
+
+ if (p.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyCaCert");
+ throw new CertPathReviewerException(msg);
+ }
+
+ if (p.onlyContainsAttributeCerts())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyAttrCert");
+ throw new CertPathReviewerException(msg);
+ }
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noValidCrlFound");
+ throw new CertPathReviewerException(msg);
+ }
+
+ }
+
+ protected Vector getCRLDistUrls(CRLDistPoint crlDistPoints)
+ {
+ Vector urls = new Vector();
+
+ if (crlDistPoints != null)
+ {
+ DistributionPoint[] distPoints = crlDistPoints.getDistributionPoints();
+ for (int i = 0; i < distPoints.length; i++)
+ {
+ DistributionPointName dp_name = distPoints[i].getDistributionPoint();
+ if (dp_name.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] generalNames = GeneralNames.getInstance(dp_name.getName()).getNames();
+ for (int j = 0; j < generalNames.length; j++)
+ {
+ if (generalNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
+ {
+ String url = ((DERIA5String) generalNames[j].getName()).getString();
+ urls.add(url);
+ }
+ }
+ }
+ }
+ }
+ return urls;
+ }
+
+ protected Vector getOCSPUrls(AuthorityInformationAccess authInfoAccess)
+ {
+ Vector urls = new Vector();
+
+ if (authInfoAccess != null)
+ {
+ AccessDescription[] ads = authInfoAccess.getAccessDescriptions();
+ for (int i = 0; i < ads.length; i++)
+ {
+ if (ads[i].getAccessMethod().equals(AccessDescription.id_ad_ocsp))
+ {
+ GeneralName name = ads[i].getAccessLocation();
+ if (name.getTagNo() == GeneralName.uniformResourceIdentifier)
+ {
+ String url = ((DERIA5String) name.getName()).getString();
+ urls.add(url);
+ }
+ }
+ }
+ }
+
+ return urls;
+ }
+
+ private X509CRL getCRL(String location) throws CertPathReviewerException
+ {
+ X509CRL result = null;
+ try
+ {
+ URL url = new URL(location);
+
+ if (url.getProtocol().equals("http") || url.getProtocol().equals("https"))
+ {
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setUseCaches(false);
+ //conn.setConnectTimeout(2000);
+ conn.setDoInput(true);
+ conn.connect();
+ if (conn.getResponseCode() == HttpURLConnection.HTTP_OK)
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509","SC");
+ result = (X509CRL) cf.generateCRL(conn.getInputStream());
+ }
+ else
+ {
+ throw new Exception(conn.getResponseMessage());
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.loadCrlDistPointError",
+ new Object[] {new UntrustedInput(location),
+ e.getMessage(),e,e.getClass().getName()});
+ throw new CertPathReviewerException(msg);
+ }
+ return result;
+ }
+
+ protected Collection getTrustAnchors(X509Certificate cert, Set trustanchors) throws CertPathReviewerException
+ {
+ Collection trustColl = new ArrayList();
+ Iterator it = trustanchors.iterator();
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+
+ try
+ {
+ certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded());
+ byte[] ext = cert.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (ext != null)
+ {
+ ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(ext);
+ AuthorityKeyIdentifier authID = AuthorityKeyIdentifier.getInstance(ASN1Primitive.fromByteArray(oct.getOctets()));
+
+ certSelectX509.setSerialNumber(authID.getAuthorityCertSerialNumber());
+ byte[] keyID = authID.getKeyIdentifier();
+ if (keyID != null)
+ {
+ certSelectX509.setSubjectKeyIdentifier(new DEROctetString(keyID).getEncoded());
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustAnchorIssuerError");
+ throw new CertPathReviewerException(msg);
+ }
+
+ while (it.hasNext())
+ {
+ TrustAnchor trust = (TrustAnchor) it.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustColl.add(trust);
+ }
+ }
+ else if (trust.getCAName() != null && trust.getCAPublicKey() != null)
+ {
+ X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
+ X500Principal caName = new X500Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustColl.add(trust);
+ }
+ }
+ }
+ return trustColl;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Attribute.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Attribute.java
new file mode 100644
index 000000000..57a826e59
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Attribute.java
@@ -0,0 +1,79 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.x509.Attribute;
+
+/**
+ * Class for carrying the values in an X.509 Attribute.
+ */
+public class X509Attribute
+ extends ASN1Object
+{
+ Attribute attr;
+
+ /**
+ * @param at an object representing an attribute.
+ */
+ X509Attribute(
+ ASN1Encodable at)
+ {
+ this.attr = Attribute.getInstance(at);
+ }
+
+ /**
+ * Create an X.509 Attribute with the type given by the passed in oid and
+ * the value represented by an ASN.1 Set containing value.
+ *
+ * @param oid type of the attribute
+ * @param value value object to go into the atribute's value set.
+ */
+ public X509Attribute(
+ String oid,
+ ASN1Encodable value)
+ {
+ this.attr = new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value));
+ }
+
+ /**
+ * Create an X.59 Attribute with the type given by the passed in oid and the
+ * value represented by an ASN.1 Set containing the objects in value.
+ *
+ * @param oid type of the attribute
+ * @param value vector of values to go in the attribute's value set.
+ */
+ public X509Attribute(
+ String oid,
+ ASN1EncodableVector value)
+ {
+ this.attr = new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value));
+ }
+
+ public String getOID()
+ {
+ return attr.getAttrType().getId();
+ }
+
+ public ASN1Encodable[] getValues()
+ {
+ ASN1Set s = attr.getAttrValues();
+ ASN1Encodable[] values = new ASN1Encodable[s.size()];
+
+ for (int i = 0; i != s.size(); i++)
+ {
+ values[i] = (ASN1Encodable)s.getObjectAt(i);
+ }
+
+ return values;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return attr.toASN1Primitive();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509AttributeCertStoreSelector.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509AttributeCertStoreSelector.java
new file mode 100644
index 000000000..e60179562
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509AttributeCertStoreSelector.java
@@ -0,0 +1,484 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.Target;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.Targets;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Selector;
+
+/**
+ * This class is an <code>Selector</code> like implementation to select
+ * attribute certificates from a given set of criteria.
+ *
+ * @see org.spongycastle.x509.X509AttributeCertificate
+ * @see org.spongycastle.x509.X509Store
+ * @deprecated use org.spongycastle.cert.X509AttributeCertificateSelector and org.spongycastle.cert.X509AttributeCertificateSelectorBuilder.
+ */
+public class X509AttributeCertStoreSelector
+ implements Selector
+{
+
+ // TODO: name constraints???
+
+ private AttributeCertificateHolder holder;
+
+ private AttributeCertificateIssuer issuer;
+
+ private BigInteger serialNumber;
+
+ private Date attributeCertificateValid;
+
+ private X509AttributeCertificate attributeCert;
+
+ private Collection targetNames = new HashSet();
+
+ private Collection targetGroups = new HashSet();
+
+ public X509AttributeCertStoreSelector()
+ {
+ super();
+ }
+
+ /**
+ * Decides if the given attribute certificate should be selected.
+ *
+ * @param obj The attribute certificate which should be checked.
+ * @return <code>true</code> if the attribute certificate can be selected,
+ * <code>false</code> otherwise.
+ */
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509AttributeCertificate))
+ {
+ return false;
+ }
+
+ X509AttributeCertificate attrCert = (X509AttributeCertificate) obj;
+
+ if (this.attributeCert != null)
+ {
+ if (!this.attributeCert.equals(attrCert))
+ {
+ return false;
+ }
+ }
+ if (serialNumber != null)
+ {
+ if (!attrCert.getSerialNumber().equals(serialNumber))
+ {
+ return false;
+ }
+ }
+ if (holder != null)
+ {
+ if (!attrCert.getHolder().equals(holder))
+ {
+ return false;
+ }
+ }
+ if (issuer != null)
+ {
+ if (!attrCert.getIssuer().equals(issuer))
+ {
+ return false;
+ }
+ }
+
+ if (attributeCertificateValid != null)
+ {
+ try
+ {
+ attrCert.checkValidity(attributeCertificateValid);
+ }
+ catch (CertificateExpiredException e)
+ {
+ return false;
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ return false;
+ }
+ }
+ if (!targetNames.isEmpty() || !targetGroups.isEmpty())
+ {
+
+ byte[] targetInfoExt = attrCert
+ .getExtensionValue(X509Extensions.TargetInformation.getId());
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation
+ .getInstance(new ASN1InputStream(
+ ((DEROctetString) DEROctetString
+ .fromByteArray(targetInfoExt)).getOctets())
+ .readObject());
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+ Targets[] targetss = targetinfo.getTargetsObjects();
+ if (!targetNames.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetNames.contains(GeneralName.getInstance(targets[j]
+ .getTargetName())))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ if (!targetGroups.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetGroups.contains(GeneralName.getInstance(targets[j]
+ .getTargetGroup())))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return the clone.
+ */
+ public Object clone()
+ {
+ X509AttributeCertStoreSelector sel = new X509AttributeCertStoreSelector();
+ sel.attributeCert = attributeCert;
+ sel.attributeCertificateValid = getAttributeCertificateValid();
+ sel.holder = holder;
+ sel.issuer = issuer;
+ sel.serialNumber = serialNumber;
+ sel.targetGroups = getTargetGroups();
+ sel.targetNames = getTargetNames();
+ return sel;
+ }
+
+ /**
+ * Returns the attribute certificate which must be matched.
+ *
+ * @return Returns the attribute certificate.
+ */
+ public X509AttributeCertificate getAttributeCert()
+ {
+ return attributeCert;
+ }
+
+ /**
+ * Set the attribute certificate to be matched. If <code>null</code> is
+ * given any will do.
+ *
+ * @param attributeCert The attribute certificate to set.
+ */
+ public void setAttributeCert(X509AttributeCertificate attributeCert)
+ {
+ this.attributeCert = attributeCert;
+ }
+
+ /**
+ * Get the criteria for the validity.
+ *
+ * @return Returns the attributeCertificateValid.
+ */
+ public Date getAttributeCertificateValid()
+ {
+ if (attributeCertificateValid != null)
+ {
+ return new Date(attributeCertificateValid.getTime());
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the time, when the certificate must be valid. If <code>null</code>
+ * is given any will do.
+ *
+ * @param attributeCertificateValid The attribute certificate validation
+ * time to set.
+ */
+ public void setAttributeCertificateValid(Date attributeCertificateValid)
+ {
+ if (attributeCertificateValid != null)
+ {
+ this.attributeCertificateValid = new Date(attributeCertificateValid
+ .getTime());
+ }
+ else
+ {
+ this.attributeCertificateValid = null;
+ }
+ }
+
+ /**
+ * Gets the holder.
+ *
+ * @return Returns the holder.
+ */
+ public AttributeCertificateHolder getHolder()
+ {
+ return holder;
+ }
+
+ /**
+ * Sets the holder. If <code>null</code> is given any will do.
+ *
+ * @param holder The holder to set.
+ */
+ public void setHolder(AttributeCertificateHolder holder)
+ {
+ this.holder = holder;
+ }
+
+ /**
+ * Returns the issuer criterion.
+ *
+ * @return Returns the issuer.
+ */
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return issuer;
+ }
+
+ /**
+ * Sets the issuer the attribute certificate must have. If <code>null</code>
+ * is given any will do.
+ *
+ * @param issuer The issuer to set.
+ */
+ public void setIssuer(AttributeCertificateIssuer issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ /**
+ * Gets the serial number the attribute certificate must have.
+ *
+ * @return Returns the serialNumber.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ /**
+ * Sets the serial number the attribute certificate must have. If
+ * <code>null</code> is given any will do.
+ *
+ * @param serialNumber The serialNumber to set.
+ */
+ public void setSerialNumber(BigInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name The name as a GeneralName (not <code>null</code>)
+ */
+ public void addTargetName(GeneralName name)
+ {
+ targetNames.add(name);
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void addTargetName(byte[] name) throws IOException
+ {
+ addTargetName(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target names criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of either GeneralName objects or byte[] arrays representing
+ * DER encoded GeneralName structures.
+ *
+ * @param names A collection of target names.
+ * @throws IOException if a parsing error occurs.
+ * @see #addTargetName(byte[])
+ * @see #addTargetName(GeneralName)
+ */
+ public void setTargetNames(Collection names) throws IOException
+ {
+ targetNames = extractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target names. The collection consists of <code>GeneralName</code>
+ * objects.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ * @see #setTargetNames(Collection)
+ */
+ public Collection getTargetNames()
+ {
+ return Collections.unmodifiableCollection(targetNames);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param group The group as GeneralName form (not <code>null</code>)
+ */
+ public void addTargetGroup(GeneralName group)
+ {
+ targetGroups.add(group);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void addTargetGroup(byte[] name) throws IOException
+ {
+ addTargetGroup(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target groups criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER
+ * encoded GeneralNames.
+ *
+ * @param names A collection of target groups.
+ * @throws IOException if a parsing error occurs.
+ * @see #addTargetGroup(byte[])
+ * @see #addTargetGroup(GeneralName)
+ */
+ public void setTargetGroups(Collection names) throws IOException
+ {
+ targetGroups = extractGeneralNames(names);
+ }
+
+
+
+ /**
+ * Gets the target groups. The collection consists of <code>GeneralName</code> objects.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ * @see #setTargetGroups(Collection)
+ */
+ public Collection getTargetGroups()
+ {
+ return Collections.unmodifiableCollection(targetGroups);
+ }
+
+ private Set extractGeneralNames(Collection names)
+ throws IOException
+ {
+ if (names == null || names.isEmpty())
+ {
+ return new HashSet();
+ }
+ Set temp = new HashSet();
+ for (Iterator it = names.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+ if (o instanceof GeneralName)
+ {
+ temp.add(o);
+ }
+ else
+ {
+ temp.add(GeneralName.getInstance(ASN1Primitive.fromByteArray((byte[])o)));
+ }
+ }
+ return temp;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509AttributeCertificate.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509AttributeCertificate.java
new file mode 100644
index 000000000..e0f663c2e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509AttributeCertificate.java
@@ -0,0 +1,101 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Extension;
+import java.util.Date;
+
+/**
+ * Interface for an X.509 Attribute Certificate.
+ */
+public interface X509AttributeCertificate
+ extends X509Extension
+{
+ /**
+ * Return the version number for the certificate.
+ *
+ * @return the version number.
+ */
+ public int getVersion();
+
+ /**
+ * Return the serial number for the certificate.
+ *
+ * @return the serial number.
+ */
+ public BigInteger getSerialNumber();
+
+ /**
+ * Return the date before which the certificate is not valid.
+ *
+ * @return the "not valid before" date.
+ */
+ public Date getNotBefore();
+
+ /**
+ * Return the date after which the certificate is not valid.
+ *
+ * @return the "not valid afer" date.
+ */
+ public Date getNotAfter();
+
+ /**
+ * Return the holder of the certificate.
+ *
+ * @return the holder.
+ */
+ public AttributeCertificateHolder getHolder();
+
+ /**
+ * Return the issuer details for the certificate.
+ *
+ * @return the issuer details.
+ */
+ public AttributeCertificateIssuer getIssuer();
+
+ /**
+ * Return the attributes contained in the attribute block in the certificate.
+ *
+ * @return an array of attributes.
+ */
+ public X509Attribute[] getAttributes();
+
+ /**
+ * Return the attributes with the same type as the passed in oid.
+ *
+ * @param oid the object identifier we wish to match.
+ * @return an array of matched attributes, null if there is no match.
+ */
+ public X509Attribute[] getAttributes(String oid);
+
+ public boolean[] getIssuerUniqueID();
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException;
+
+ public void checkValidity(Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException;
+
+ public byte[] getSignature();
+
+ public void verify(PublicKey key, String provider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException;
+
+ /**
+ * Return an ASN.1 encoded byte array representing the attribute certificate.
+ *
+ * @return an ASN.1 encoded byte array.
+ * @throws IOException if the certificate cannot be encoded.
+ */
+ public byte[] getEncoded()
+ throws IOException;
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CRLStoreSelector.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CRLStoreSelector.java
new file mode 100644
index 000000000..8572afa53
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CRLStoreSelector.java
@@ -0,0 +1,330 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRL;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLSelector;
+
+/**
+ * This class is a Selector implementation for X.509 certificate revocation
+ * lists.
+ *
+ * @see org.spongycastle.util.Selector
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.jce.provider.X509StoreCRLCollection
+ */
+public class X509CRLStoreSelector
+ extends X509CRLSelector
+ implements Selector
+{
+ private boolean deltaCRLIndicator = false;
+
+ private boolean completeCRLEnabled = false;
+
+ private BigInteger maxBaseCRLNumber = null;
+
+ private byte[] issuingDistributionPoint = null;
+
+ private boolean issuingDistributionPointEnabled = false;
+
+ private X509AttributeCertificate attrCertChecking;
+
+ /**
+ * Returns if the issuing distribution point criteria should be applied.
+ * Defaults to <code>false</code>.
+ * <p>
+ * You may also set the issuing distribution point criteria if not a missing
+ * issuing distribution point should be assumed.
+ *
+ * @return Returns if the issuing distribution point check is enabled.
+ */
+ public boolean isIssuingDistributionPointEnabled()
+ {
+ return issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Enables or disables the issuing distribution point check.
+ *
+ * @param issuingDistributionPointEnabled <code>true</code> to enable the
+ * issuing distribution point check.
+ */
+ public void setIssuingDistributionPointEnabled(
+ boolean issuingDistributionPointEnabled)
+ {
+ this.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Sets the attribute certificate being checked. This is not a criterion.
+ * Rather, it is optional information that may help a {@link X509Store} find
+ * CRLs that would be relevant when checking revocation for the specified
+ * attribute certificate. If <code>null</code> is specified, then no such
+ * optional information is provided.
+ *
+ * @param attrCert the <code>X509AttributeCertificate</code> being checked (or
+ * <code>null</code>)
+ * @see #getAttrCertificateChecking()
+ */
+ public void setAttrCertificateChecking(X509AttributeCertificate attrCert)
+ {
+ attrCertChecking = attrCert;
+ }
+
+ /**
+ * Returns the attribute certificate being checked.
+ *
+ * @return Returns the attribute certificate being checked.
+ * @see #setAttrCertificateChecking(X509AttributeCertificate)
+ */
+ public X509AttributeCertificate getAttrCertificateChecking()
+ {
+ return attrCertChecking;
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509CRL))
+ {
+ return false;
+ }
+ X509CRL crl = (X509CRL)obj;
+ DERInteger dci = null;
+ try
+ {
+ byte[] bytes = crl
+ .getExtensionValue(X509Extensions.DeltaCRLIndicator.getId());
+ if (bytes != null)
+ {
+ dci = DERInteger.getInstance(X509ExtensionUtil
+ .fromExtensionValue(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ if (isDeltaCRLIndicatorEnabled())
+ {
+ if (dci == null)
+ {
+ return false;
+ }
+ }
+ if (isCompleteCRLEnabled())
+ {
+ if (dci != null)
+ {
+ return false;
+ }
+ }
+ if (dci != null)
+ {
+
+ if (maxBaseCRLNumber != null)
+ {
+ if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1)
+ {
+ return false;
+ }
+ }
+ }
+ if (issuingDistributionPointEnabled)
+ {
+ byte[] idp = crl
+ .getExtensionValue(X509Extensions.IssuingDistributionPoint
+ .getId());
+ if (issuingDistributionPoint == null)
+ {
+ if (idp != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!Arrays.areEqual(idp, issuingDistributionPoint))
+ {
+ return false;
+ }
+ }
+
+ }
+ return super.match((X509CRL)obj);
+ }
+
+ public boolean match(CRL crl)
+ {
+ return match((Object)crl);
+ }
+
+ /**
+ * Returns if this selector must match CRLs with the delta CRL indicator
+ * extension set. Defaults to <code>false</code>.
+ *
+ * @return Returns <code>true</code> if only CRLs with the delta CRL
+ * indicator extension are selected.
+ */
+ public boolean isDeltaCRLIndicatorEnabled()
+ {
+ return deltaCRLIndicator;
+ }
+
+ /**
+ * If this is set to <code>true</code> the CRL reported contains the delta
+ * CRL indicator CRL extension.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator
+ * extension must be in the CRL.
+ */
+ public void setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator)
+ {
+ this.deltaCRLIndicator = deltaCRLIndicator;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CRLSelector</code>.
+ *
+ * @param selector A <code>X509CRLSelector</code> instance.
+ * @return An instance of an <code>X509CRLStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation
+ * fails.
+ */
+ public static X509CRLStoreSelector getInstance(X509CRLSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException(
+ "cannot create from null selector");
+ }
+ X509CRLStoreSelector cs = new X509CRLStoreSelector();
+ cs.setCertificateChecking(selector.getCertificateChecking());
+ cs.setDateAndTime(selector.getDateAndTime());
+ try
+ {
+ cs.setIssuerNames(selector.getIssuerNames());
+ }
+ catch (IOException e)
+ {
+ // cannot happen
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ cs.setIssuers(selector.getIssuers());
+ cs.setMaxCRLNumber(selector.getMaxCRL());
+ cs.setMinCRLNumber(selector.getMinCRL());
+ return cs;
+ }
+
+ public Object clone()
+ {
+ X509CRLStoreSelector sel = X509CRLStoreSelector.getInstance(this);
+ sel.deltaCRLIndicator = deltaCRLIndicator;
+ sel.completeCRLEnabled = completeCRLEnabled;
+ sel.maxBaseCRLNumber = maxBaseCRLNumber;
+ sel.attrCertChecking = attrCertChecking;
+ sel.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ sel.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ return sel;
+ }
+
+ /**
+ * If <code>true</code> only complete CRLs are returned. Defaults to
+ * <code>false</code>.
+ *
+ * @return <code>true</code> if only complete CRLs are returned.
+ */
+ public boolean isCompleteCRLEnabled()
+ {
+ return completeCRLEnabled;
+ }
+
+ /**
+ * If set to <code>true</code> only complete CRLs are returned.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param completeCRLEnabled <code>true</code> if only complete CRLs
+ * should be returned.
+ */
+ public void setCompleteCRLEnabled(boolean completeCRLEnabled)
+ {
+ this.completeCRLEnabled = completeCRLEnabled;
+ }
+
+ /**
+ * Get the maximum base CRL number. Defaults to <code>null</code>.
+ *
+ * @return Returns the maximum base CRL number.
+ * @see #setMaxBaseCRLNumber(BigInteger)
+ */
+ public BigInteger getMaxBaseCRLNumber()
+ {
+ return maxBaseCRLNumber;
+ }
+
+ /**
+ * Sets the maximum base CRL number. Setting to <code>null</code> disables
+ * this cheack.
+ * <p>
+ * This is only meaningful for delta CRLs. Complete CRLs must have a CRL
+ * number which is greater or equal than the base number of the
+ * corresponding CRL.
+ *
+ * @param maxBaseCRLNumber The maximum base CRL number to set.
+ */
+ public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber)
+ {
+ this.maxBaseCRLNumber = maxBaseCRLNumber;
+ }
+
+ /**
+ * Returns the issuing distribution point. Defaults to <code>null</code>,
+ * which is a missing issuing distribution point extension.
+ * <p>
+ * The internal byte array is cloned before it is returned.
+ * <p>
+ * The criteria must be enable with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @return Returns the issuing distribution point.
+ * @see #setIssuingDistributionPoint(byte[])
+ */
+ public byte[] getIssuingDistributionPoint()
+ {
+ return Arrays.clone(issuingDistributionPoint);
+ }
+
+ /**
+ * Sets the issuing distribution point.
+ * <p>
+ * The issuing distribution point extension is a CRL extension which
+ * identifies the scope and the distribution point of a CRL. The scope
+ * contains among others information about revocation reasons contained in
+ * the CRL. Delta CRLs and complete CRLs must have matching issuing
+ * distribution points.
+ * <p>
+ * The byte array is cloned to protect against subsequent modifications.
+ * <p>
+ * You must also enable or disable this criteria with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @param issuingDistributionPoint The issuing distribution point to set.
+ * This is the DER encoded OCTET STRING extension value.
+ * @see #getIssuingDistributionPoint()
+ */
+ public void setIssuingDistributionPoint(byte[] issuingDistributionPoint)
+ {
+ this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertPairStoreSelector.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertPairStoreSelector.java
new file mode 100644
index 000000000..e5676bcb1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertPairStoreSelector.java
@@ -0,0 +1,155 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+/**
+ * This class is an <code>Selector</code> like implementation to select
+ * certificates pairs, which are e.g. used for cross certificates. The set of
+ * criteria is given from two
+ * {@link org.spongycastle.x509.X509CertStoreSelector}s which must be both
+ * matched.
+ *
+ * @see org.spongycastle.x509.X509AttributeCertificate
+ * @see org.spongycastle.x509.X509Store
+ */
+public class X509CertPairStoreSelector implements Selector
+{
+
+ private X509CertStoreSelector forwardSelector;
+
+ private X509CertStoreSelector reverseSelector;
+
+ private X509CertificatePair certPair;
+
+ public X509CertPairStoreSelector()
+ {
+ }
+
+ /**
+ * Returns the certificate pair which is used for testing on equality.
+ *
+ * @return Returns the certificate pair which is checked.
+ */
+ public X509CertificatePair getCertPair()
+ {
+ return certPair;
+ }
+
+ /**
+ * Set the certificate pair which is used for testing on equality.
+ *
+ * @param certPair The certPairChecking to set.
+ */
+ public void setCertPair(X509CertificatePair certPair)
+ {
+ this.certPair = certPair;
+ }
+
+ /**
+ * @param forwardSelector The certificate selector for the forward part in
+ * the pair.
+ */
+ public void setForwardSelector(X509CertStoreSelector forwardSelector)
+ {
+ this.forwardSelector = forwardSelector;
+ }
+
+ /**
+ * @param reverseSelector The certificate selector for the reverse part in
+ * the pair.
+ */
+ public void setReverseSelector(X509CertStoreSelector reverseSelector)
+ {
+ this.reverseSelector = reverseSelector;
+ }
+
+ /**
+ * Returns a clone of this selector.
+ *
+ * @return A clone of this selector.
+ * @see java.lang.Object#clone()
+ */
+ public Object clone()
+ {
+ X509CertPairStoreSelector cln = new X509CertPairStoreSelector();
+
+ cln.certPair = certPair;
+
+ if (forwardSelector != null)
+ {
+ cln.setForwardSelector((X509CertStoreSelector) forwardSelector
+ .clone());
+ }
+
+ if (reverseSelector != null)
+ {
+ cln.setReverseSelector((X509CertStoreSelector) reverseSelector
+ .clone());
+ }
+
+ return cln;
+ }
+
+ /**
+ * Decides if the given certificate pair should be selected. If
+ * <code>obj</code> is not a {@link X509CertificatePair} this method
+ * returns <code>false</code>.
+ *
+ * @param obj The {@link X509CertificatePair} which should be tested.
+ * @return <code>true</code> if the object matches this selector.
+ */
+ public boolean match(Object obj)
+ {
+ try
+ {
+ if (!(obj instanceof X509CertificatePair))
+ {
+ return false;
+ }
+ X509CertificatePair pair = (X509CertificatePair)obj;
+
+ if (forwardSelector != null
+ && !forwardSelector.match((Object)pair.getForward()))
+ {
+ return false;
+ }
+
+ if (reverseSelector != null
+ && !reverseSelector.match((Object)pair.getReverse()))
+ {
+ return false;
+ }
+
+ if (certPair != null)
+ {
+ return certPair.equals(obj);
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the certicate selector for the forward part.
+ *
+ * @return Returns the certicate selector for the forward part.
+ */
+ public X509CertStoreSelector getForwardSelector()
+ {
+ return forwardSelector;
+ }
+
+ /**
+ * Returns the certicate selector for the reverse part.
+ *
+ * @return Returns the reverse selector for teh reverse part.
+ */
+ public X509CertStoreSelector getReverseSelector()
+ {
+ return reverseSelector;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertStoreSelector.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertStoreSelector.java
new file mode 100644
index 000000000..80ea1c3ab
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertStoreSelector.java
@@ -0,0 +1,87 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.io.IOException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+
+/**
+ * This class is a Selector implementation for X.509 certificates.
+ *
+ * @see org.spongycastle.util.Selector
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.jce.provider.X509StoreCertCollection
+ */
+public class X509CertStoreSelector
+ extends X509CertSelector
+ implements Selector
+{
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate other = (X509Certificate)obj;
+
+ return super.match(other);
+ }
+
+ public boolean match(Certificate cert)
+ {
+ return match((Object)cert);
+ }
+
+ public Object clone()
+ {
+ X509CertStoreSelector selector = (X509CertStoreSelector)super.clone();
+
+ return selector;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CertSelector</code>.
+ *
+ * @param selector A <code>X509CertSelector</code> instance.
+ * @return An instance of an <code>X509CertStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation fails.
+ */
+ public static X509CertStoreSelector getInstance(X509CertSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException("cannot create from null selector");
+ }
+ X509CertStoreSelector cs = new X509CertStoreSelector();
+ cs.setAuthorityKeyIdentifier(selector.getAuthorityKeyIdentifier());
+ cs.setBasicConstraints(selector.getBasicConstraints());
+ cs.setCertificate(selector.getCertificate());
+ cs.setCertificateValid(selector.getCertificateValid());
+ cs.setMatchAllSubjectAltNames(selector.getMatchAllSubjectAltNames());
+ try
+ {
+ cs.setPathToNames(selector.getPathToNames());
+ cs.setExtendedKeyUsage(selector.getExtendedKeyUsage());
+ cs.setNameConstraints(selector.getNameConstraints());
+ cs.setPolicy(selector.getPolicy());
+ cs.setSubjectPublicKeyAlgID(selector.getSubjectPublicKeyAlgID());
+ cs.setSubjectAlternativeNames(selector.getSubjectAlternativeNames());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error in passed in selector: " + e);
+ }
+ cs.setIssuer(selector.getIssuer());
+ cs.setKeyUsage(selector.getKeyUsage());
+ cs.setPrivateKeyValid(selector.getPrivateKeyValid());
+ cs.setSerialNumber(selector.getSerialNumber());
+ cs.setSubject(selector.getSubject());
+ cs.setSubjectKeyIdentifier(selector.getSubjectKeyIdentifier());
+ cs.setSubjectPublicKey(selector.getSubjectPublicKey());
+ return cs;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertificatePair.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertificatePair.java
new file mode 100644
index 000000000..39c0b407c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CertificatePair.java
@@ -0,0 +1,167 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificatePair;
+import org.spongycastle.jce.provider.X509CertificateObject;
+
+/**
+ * This class contains a cross certificate pair. Cross certificates pairs may
+ * contain two cross signed certificates from two CAs. A certificate from the
+ * other CA to this CA is contained in the forward certificate, the certificate
+ * from this CA to the other CA is contained in the reverse certificate.
+ */
+public class X509CertificatePair
+{
+ private X509Certificate forward;
+ private X509Certificate reverse;
+
+ /**
+ * Constructor.
+ *
+ * @param forward Certificate from the other CA to this CA.
+ * @param reverse Certificate from this CA to the other CA.
+ */
+ public X509CertificatePair(
+ X509Certificate forward,
+ X509Certificate reverse)
+ {
+ this.forward = forward;
+ this.reverse = reverse;
+ }
+
+ /**
+ * Constructor from a ASN.1 CertificatePair structure.
+ *
+ * @param pair The <code>CertificatePair</code> ASN.1 object.
+ */
+ public X509CertificatePair(
+ CertificatePair pair)
+ throws CertificateParsingException
+ {
+ if (pair.getForward() != null)
+ {
+ this.forward = new X509CertificateObject(pair.getForward());
+ }
+ if (pair.getReverse() != null)
+ {
+ this.reverse = new X509CertificateObject(pair.getReverse());
+ }
+ }
+
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ Certificate f = null;
+ Certificate r = null;
+ try
+ {
+ if (forward != null)
+ {
+ f = Certificate.getInstance(new ASN1InputStream(
+ forward.getEncoded()).readObject());
+ if (f == null)
+ {
+ throw new CertificateEncodingException("unable to get encoding for forward");
+ }
+ }
+ if (reverse != null)
+ {
+ r = Certificate.getInstance(new ASN1InputStream(
+ reverse.getEncoded()).readObject());
+ if (r == null)
+ {
+ throw new CertificateEncodingException("unable to get encoding for reverse");
+ }
+ }
+ return new CertificatePair(f, r).getEncoded(ASN1Encoding.DER);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertificateEncodingException(e.toString(), e);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException(e.toString(), e);
+ }
+ }
+
+ /**
+ * Returns the certificate from the other CA to this CA.
+ *
+ * @return Returns the forward certificate.
+ */
+ public X509Certificate getForward()
+ {
+ return forward;
+ }
+
+ /**
+ * Return the certificate from this CA to the other CA.
+ *
+ * @return Returns the reverse certificate.
+ */
+ public X509Certificate getReverse()
+ {
+ return reverse;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == null)
+ {
+ return false;
+ }
+ if (!(o instanceof X509CertificatePair))
+ {
+ return false;
+ }
+ X509CertificatePair pair = (X509CertificatePair)o;
+ boolean equalReverse = true;
+ boolean equalForward = true;
+ if (forward != null)
+ {
+ equalForward = this.forward.equals(pair.forward);
+ }
+ else
+ {
+ if (pair.forward != null)
+ {
+ equalForward = false;
+ }
+ }
+ if (reverse != null)
+ {
+ equalReverse = this.reverse.equals(pair.reverse);
+ }
+ else
+ {
+ if (pair.reverse != null)
+ {
+ equalReverse = false;
+ }
+ }
+ return equalForward && equalReverse;
+ }
+
+ public int hashCode()
+ {
+ int hash = -1;
+ if (forward != null)
+ {
+ hash ^= forward.hashCode();
+ }
+ if (reverse != null)
+ {
+ hash *= 17;
+ hash ^= reverse.hashCode();
+ }
+ return hash;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CollectionStoreParameters.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CollectionStoreParameters.java
new file mode 100644
index 000000000..eb3887710
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509CollectionStoreParameters.java
@@ -0,0 +1,70 @@
+package org.spongycastle.x509;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * This class contains a collection for collection based <code>X509Store</code>s.
+ *
+ * @see org.spongycastle.x509.X509Store
+ *
+ */
+public class X509CollectionStoreParameters
+ implements X509StoreParameters
+{
+ private Collection collection;
+
+ /**
+ * Constructor.
+ * <p>
+ * The collection is copied.
+ * </p>
+ *
+ * @param collection
+ * The collection containing X.509 object types.
+ * @throws NullPointerException if <code>collection</code> is <code>null</code>.
+ */
+ public X509CollectionStoreParameters(Collection collection)
+ {
+ if (collection == null)
+ {
+ throw new NullPointerException("collection cannot be null");
+ }
+ this.collection = collection;
+ }
+
+ /**
+ * Returns a shallow clone. The returned contents are not copied, so adding
+ * or removing objects will effect this.
+ *
+ * @return a shallow clone.
+ */
+ public Object clone()
+ {
+ return new X509CollectionStoreParameters(collection);
+ }
+
+ /**
+ * Returns a copy of the <code>Collection</code>.
+ *
+ * @return The <code>Collection</code>. Is never <code>null</code>.
+ */
+ public Collection getCollection()
+ {
+ return new ArrayList(collection);
+ }
+
+ /**
+ * Returns a formatted string describing the parameters.
+ *
+ * @return a formatted string describing the parameters
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("X509CollectionStoreParameters: [\n");
+ sb.append(" collection: " + collection + "\n");
+ sb.append("]");
+ return sb.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Store.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Store.java
new file mode 100644
index 000000000..94e82558d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Store.java
@@ -0,0 +1,82 @@
+package org.spongycastle.x509;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.util.Collection;
+
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.Store;
+
+/**
+ * @deprecated use CollectionStore - this class will be removed.
+ */
+public class X509Store
+ implements Store
+{
+ public static X509Store getInstance(String type, X509StoreParameters parameters)
+ throws NoSuchStoreException
+ {
+ try
+ {
+ X509Util.Implementation impl = X509Util.getImplementation("X509Store", type);
+
+ return createStore(impl, parameters);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new NoSuchStoreException(e.getMessage());
+ }
+ }
+
+ public static X509Store getInstance(String type, X509StoreParameters parameters, String provider)
+ throws NoSuchStoreException, NoSuchProviderException
+ {
+ return getInstance(type, parameters, X509Util.getProvider(provider));
+ }
+
+ public static X509Store getInstance(String type, X509StoreParameters parameters, Provider provider)
+ throws NoSuchStoreException
+ {
+ try
+ {
+ X509Util.Implementation impl = X509Util.getImplementation("X509Store", type, provider);
+
+ return createStore(impl, parameters);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new NoSuchStoreException(e.getMessage());
+ }
+ }
+
+ private static X509Store createStore(X509Util.Implementation impl, X509StoreParameters parameters)
+ {
+ X509StoreSpi spi = (X509StoreSpi)impl.getEngine();
+
+ spi.engineInit(parameters);
+
+ return new X509Store(impl.getProvider(), spi);
+ }
+
+ private Provider _provider;
+ private X509StoreSpi _spi;
+
+ private X509Store(
+ Provider provider,
+ X509StoreSpi spi)
+ {
+ _provider = provider;
+ _spi = spi;
+ }
+
+ public Provider getProvider()
+ {
+ return _provider;
+ }
+
+ public Collection getMatches(Selector selector)
+ {
+ return _spi.engineGetMatches(selector);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StoreParameters.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StoreParameters.java
new file mode 100644
index 000000000..38a65abbe
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StoreParameters.java
@@ -0,0 +1,5 @@
+package org.spongycastle.x509;
+
+public interface X509StoreParameters
+{
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StoreSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StoreSpi.java
new file mode 100644
index 000000000..74d1d4d32
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StoreSpi.java
@@ -0,0 +1,12 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.util.Collection;
+
+public abstract class X509StoreSpi
+{
+ public abstract void engineInit(X509StoreParameters parameters);
+
+ public abstract Collection engineGetMatches(Selector selector);
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StreamParser.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StreamParser.java
new file mode 100644
index 000000000..3aebe07ce
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StreamParser.java
@@ -0,0 +1,161 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.x509.util.StreamParser;
+import org.spongycastle.x509.util.StreamParsingException;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.util.Collection;
+
+/**
+ *
+ * This class allows access to different implementations for reading X.509
+ * objects from streams.
+ * <p>
+ * A X509StreamParser is used to read a collection of objects or a single object
+ * of a certain X.509 object structure. E.g. one X509StreamParser can read
+ * certificates, another one CRLs, certification paths, attribute certificates
+ * and so on. The kind of object structure is specified with the
+ * <code>algorithm</code> parameter to the <code>getInstance</code> methods.
+ * <p>
+ * Implementations must implement the
+ * {@link org.spongycastle.x509.X509StreamParserSpi}.
+ */
+public class X509StreamParser
+ implements StreamParser
+{
+ /**
+ * Generates a StreamParser object that implements the specified type. If
+ * the default provider package provides an implementation of the requested
+ * type, an instance of StreamParser containing that implementation is
+ * returned. If the type is not available in the default package, other
+ * packages are searched.
+ *
+ * @param type
+ * The name of the requested X.509 object type.
+ * @return a StreamParser object for the specified type.
+ *
+ * @exception NoSuchParserException
+ * if the requested type is not available in the default
+ * provider package or any of the other provider packages
+ * that were searched.
+ */
+ public static X509StreamParser getInstance(String type)
+ throws NoSuchParserException
+ {
+ try
+ {
+ X509Util.Implementation impl = X509Util.getImplementation("X509StreamParser", type);
+
+ return createParser(impl);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new NoSuchParserException(e.getMessage());
+ }
+ }
+
+ /**
+ * Generates a X509StreamParser object for the specified type from the
+ * specified provider.
+ *
+ * @param type
+ * the name of the requested X.509 object type.
+ * @param provider
+ * the name of the provider.
+ *
+ * @return a X509StreamParser object for the specified type.
+ *
+ * @exception NoSuchParserException
+ * if the type is not available from the specified provider.
+ *
+ * @exception NoSuchProviderException
+ * if the provider can not be found.
+ *
+ * @see Provider
+ */
+ public static X509StreamParser getInstance(String type, String provider)
+ throws NoSuchParserException, NoSuchProviderException
+ {
+ return getInstance(type, X509Util.getProvider(provider));
+ }
+
+ /**
+ * Generates a X509StreamParser object for the specified type from the
+ * specified provider.
+ *
+ * @param type
+ * the name of the requested X.509 object type.
+ * @param provider
+ * the Provider to use.
+ *
+ * @return a X509StreamParser object for the specified type.
+ *
+ * @exception NoSuchParserException
+ * if the type is not available from the specified provider.
+ *
+ * @see Provider
+ */
+ public static X509StreamParser getInstance(String type, Provider provider)
+ throws NoSuchParserException
+ {
+ try
+ {
+ X509Util.Implementation impl = X509Util.getImplementation("X509StreamParser", type, provider);
+
+ return createParser(impl);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new NoSuchParserException(e.getMessage());
+ }
+ }
+
+ private static X509StreamParser createParser(X509Util.Implementation impl)
+ {
+ X509StreamParserSpi spi = (X509StreamParserSpi)impl.getEngine();
+
+ return new X509StreamParser(impl.getProvider(), spi);
+ }
+
+ private Provider _provider;
+ private X509StreamParserSpi _spi;
+
+ private X509StreamParser(
+ Provider provider,
+ X509StreamParserSpi spi)
+ {
+ _provider = provider;
+ _spi = spi;
+ }
+
+ public Provider getProvider()
+ {
+ return _provider;
+ }
+
+ public void init(InputStream stream)
+ {
+ _spi.engineInit(stream);
+ }
+
+ public void init(byte[] data)
+ {
+ _spi.engineInit(new ByteArrayInputStream(data));
+ }
+
+ public Object read()
+ throws StreamParsingException
+ {
+ return _spi.engineRead();
+ }
+
+ public Collection readAll()
+ throws StreamParsingException
+ {
+ return _spi.engineReadAll();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StreamParserSpi.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StreamParserSpi.java
new file mode 100644
index 000000000..814a65f93
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509StreamParserSpi.java
@@ -0,0 +1,45 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.x509.util.StreamParsingException;
+
+import java.io.InputStream;
+import java.util.Collection;
+
+/**
+ * This abstract class defines the service provider interface (SPI) for
+ * X509StreamParser.
+ *
+ * @see org.spongycastle.x509.X509StreamParser
+ *
+ */
+public abstract class X509StreamParserSpi
+{
+ /**
+ * Initializes this stream parser with the input stream.
+ *
+ * @param in The input stream.
+ */
+ public abstract void engineInit(InputStream in);
+
+ /**
+ * Returns the next X.509 object of the type of this SPI from the given
+ * input stream.
+ *
+ * @return the next X.509 object in the stream or <code>null</code> if the
+ * end of the stream is reached.
+ * @exception StreamParsingException
+ * if the object cannot be created from input stream.
+ */
+ public abstract Object engineRead() throws StreamParsingException;
+
+ /**
+ * Returns all X.509 objects of the type of this SPI from
+ * the given input stream.
+ *
+ * @return A collection of all X.509 objects in the input stream or
+ * <code>null</code> if the end of the stream is reached.
+ * @exception StreamParsingException
+ * if an object cannot be created from input stream.
+ */
+ public abstract Collection engineReadAll() throws StreamParsingException;
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Util.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Util.java
new file mode 100644
index 000000000..0bfd71e05
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509Util.java
@@ -0,0 +1,412 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.Strings;
+
+class X509Util
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+ params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ static DERObjectIdentifier getAlgorithmOID(
+ String algorithmName)
+ {
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (algorithms.containsKey(algorithmName))
+ {
+ return (DERObjectIdentifier)algorithms.get(algorithmName);
+ }
+
+ return new DERObjectIdentifier(algorithmName);
+ }
+
+ static AlgorithmIdentifier getSigAlgID(
+ DERObjectIdentifier sigOid,
+ String algorithmName)
+ {
+ if (noParams.contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (params.containsKey(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ return new AlgorithmIdentifier(sigOid, DERNull.INSTANCE);
+ }
+ }
+
+ static Iterator getAlgNames()
+ {
+ Enumeration e = algorithms.keys();
+ List l = new ArrayList();
+
+ while (e.hasMoreElements())
+ {
+ l.add(e.nextElement());
+ }
+
+ return l.iterator();
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm);
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm,
+ String provider)
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ if (provider != null)
+ {
+ return Signature.getInstance(algorithm, provider);
+ }
+ else
+ {
+ return Signature.getInstance(algorithm);
+ }
+ }
+
+ static byte[] calculateSignature(
+ DERObjectIdentifier sigOid,
+ String sigName,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName);
+
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static byte[] calculateSignature(
+ DERObjectIdentifier sigOid,
+ String sigName,
+ String provider,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName, provider);
+
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static X509Principal convertPrincipal(
+ X500Principal principal)
+ {
+ try
+ {
+ return new X509Principal(principal.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("cannot convert principal");
+ }
+ }
+
+ static class Implementation
+ {
+ Object engine;
+ Provider provider;
+
+ Implementation(
+ Object engine,
+ Provider provider)
+ {
+ this.engine = engine;
+ this.provider = provider;
+ }
+
+ Object getEngine()
+ {
+ return engine;
+ }
+
+ Provider getProvider()
+ {
+ return provider;
+ }
+ }
+
+ /**
+ * see if we can find an algorithm (or its alias and what it represents) in
+ * the property table for the given provider.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm,
+ Provider prov)
+ throws NoSuchAlgorithmException
+ {
+ algorithm = Strings.toUpperCase(algorithm);
+
+ String alias;
+
+ while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null)
+ {
+ algorithm = alias;
+ }
+
+ String className = prov.getProperty(baseName + "." + algorithm);
+
+ if (className != null)
+ {
+ try
+ {
+ Class cls;
+ ClassLoader clsLoader = prov.getClass().getClassLoader();
+
+ if (clsLoader != null)
+ {
+ cls = clsLoader.loadClass(className);
+ }
+ else
+ {
+ cls = Class.forName(className);
+ }
+
+ return new Implementation(cls.newInstance(), prov);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!");
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!");
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm + " for provider " + prov.getName());
+ }
+
+ /**
+ * return an implementation for a given algorithm/provider.
+ * If the provider is null, we grab the first avalaible who has the required algorithm.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ Provider[] prov = Security.getProviders();
+
+ //
+ // search every provider looking for the algorithm we want.
+ //
+ for (int i = 0; i != prov.length; i++)
+ {
+ //
+ // try case insensitive
+ //
+ Implementation imp = getImplementation(baseName, Strings.toUpperCase(algorithm), prov[i]);
+ if (imp != null)
+ {
+ return imp;
+ }
+
+ try
+ {
+ imp = getImplementation(baseName, algorithm, prov[i]);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // continue
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm);
+ }
+
+ static Provider getProvider(String provider)
+ throws NoSuchProviderException
+ {
+ Provider prov = Security.getProvider(provider);
+
+ if (prov == null)
+ {
+ throw new NoSuchProviderException("Provider " + provider + " not found");
+ }
+
+ return prov;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V1CertificateGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V1CertificateGenerator.java
new file mode 100644
index 000000000..5d9920c32
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V1CertificateGenerator.java
@@ -0,0 +1,377 @@
+package org.spongycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ * @deprecated use org.spongycastle.cert.X509v1CertificateBuilder.
+ */
+public class X509V1CertificateGenerator
+{
+ private V1TBSCertificateGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+
+ public X509V1CertificateGenerator()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X500Principal issuer)
+ {
+ try
+ {
+ tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X500Principal subject)
+ {
+ try
+ {
+ tbsGen.setSubject(new X509Principal(subject.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+ new ByteArrayInputStream(key.getEncoded())).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC" and the passed in source of randomness
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider and the passed in source of randomness
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateEncodingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ try
+ {
+ return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2AttributeCertificate.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2AttributeCertificate.java
new file mode 100644
index 000000000..c0d893dfb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2AttributeCertificate.java
@@ -0,0 +1,350 @@
+package org.spongycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.x509.AttributeCertificate;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.util.Arrays;
+
+/**
+ * An implementation of a version 2 X.509 Attribute Certificate.
+ * @deprecated use org.spongycastle.cert.X509AttributeCertificateHolder
+ */
+public class X509V2AttributeCertificate
+ implements X509AttributeCertificate
+{
+ private AttributeCertificate cert;
+ private Date notBefore;
+ private Date notAfter;
+
+ private static AttributeCertificate getObject(InputStream in)
+ throws IOException
+ {
+ try
+ {
+ return AttributeCertificate.getInstance(new ASN1InputStream(in).readObject());
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decoding certificate structure: " + e.toString());
+ }
+ }
+
+ public X509V2AttributeCertificate(
+ InputStream encIn)
+ throws IOException
+ {
+ this(getObject(encIn));
+ }
+
+ public X509V2AttributeCertificate(
+ byte[] encoded)
+ throws IOException
+ {
+ this(new ByteArrayInputStream(encoded));
+ }
+
+ X509V2AttributeCertificate(
+ AttributeCertificate cert)
+ throws IOException
+ {
+ this.cert = cert;
+
+ try
+ {
+ this.notAfter = cert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime().getDate();
+ this.notBefore = cert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IOException("invalid data structure in certificate!");
+ }
+ }
+
+ public int getVersion()
+ {
+ return cert.getAcinfo().getVersion().getValue().intValue() + 1;
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return cert.getAcinfo().getSerialNumber().getValue();
+ }
+
+ public AttributeCertificateHolder getHolder()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)cert.getAcinfo().getHolder().toASN1Object());
+ }
+
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return new AttributeCertificateIssuer(cert.getAcinfo().getIssuer());
+ }
+
+ public Date getNotBefore()
+ {
+ return notBefore;
+ }
+
+ public Date getNotAfter()
+ {
+ return notAfter;
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = cert.getAcinfo().getIssuerUniqueID();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.after(this.getNotAfter()))
+ {
+ throw new CertificateExpiredException("certificate expired on " + this.getNotAfter());
+ }
+
+ if (date.before(this.getNotBefore()))
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + this.getNotBefore());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return cert.getSignatureValue().getBytes();
+ }
+
+ public final void verify(
+ PublicKey key,
+ String provider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature = null;
+
+ if (!cert.getSignatureAlgorithm().equals(cert.getAcinfo().getSignature()))
+ {
+ throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
+ }
+
+ signature = Signature.getInstance(cert.getSignatureAlgorithm().getObjectId().getId(), provider);
+
+ signature.initVerify(key);
+
+ try
+ {
+ signature.update(cert.getAcinfo().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("Exception encoding certificate info object");
+ }
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new InvalidKeyException("Public key presented not for certificate signature");
+ }
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return cert.getEncoded();
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions extensions = cert.getAcinfo().getExtensions();
+
+ if (extensions != null)
+ {
+ Extension ext = extensions.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Set getExtensionOIDs(
+ boolean critical)
+ {
+ Extensions extensions = cert.getAcinfo().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical() == critical)
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extensions = getCriticalExtensionOIDs();
+
+ return extensions != null && !extensions.isEmpty();
+ }
+
+ public X509Attribute[] getAttributes()
+ {
+ ASN1Sequence seq = cert.getAcinfo().getAttributes();
+ X509Attribute[] attrs = new X509Attribute[seq.size()];
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ attrs[i] = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
+ }
+
+ return attrs;
+ }
+
+ public X509Attribute[] getAttributes(String oid)
+ {
+ ASN1Sequence seq = cert.getAcinfo().getAttributes();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ X509Attribute attr = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
+ if (attr.getOID().equals(oid))
+ {
+ list.add(attr);
+ }
+ }
+
+ if (list.size() == 0)
+ {
+ return null;
+ }
+
+ return (X509Attribute[])list.toArray(new X509Attribute[list.size()]);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof X509AttributeCertificate))
+ {
+ return false;
+ }
+
+ X509AttributeCertificate other = (X509AttributeCertificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+
+ public int hashCode()
+ {
+ try
+ {
+ return Arrays.hashCode(this.getEncoded());
+ }
+ catch (IOException e)
+ {
+ return 0;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java
new file mode 100644
index 000000000..ee3aeed84
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java
@@ -0,0 +1,269 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AttCertIssuer;
+import org.spongycastle.asn1.x509.Attribute;
+import org.spongycastle.asn1.x509.AttributeCertificate;
+import org.spongycastle.asn1.x509.AttributeCertificateInfo;
+import org.spongycastle.asn1.x509.V2AttributeCertificateInfoGenerator;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+
+/**
+ * class to produce an X.509 Version 2 AttributeCertificate.
+ * @deprecated use org.spongycastle.cert.X509v2AttributeCertificateBuilder
+ */
+public class X509V2AttributeCertificateGenerator
+{
+ private V2AttributeCertificateInfoGenerator acInfoGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V2AttributeCertificateGenerator()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * Set the Holder of this Attribute Certificate
+ */
+ public void setHolder(
+ AttributeCertificateHolder holder)
+ {
+ acInfoGen.setHolder(holder.holder);
+ }
+
+ /**
+ * Set the issuer
+ */
+ public void setIssuer(
+ AttributeCertificateIssuer issuer)
+ {
+ acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form));
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ acInfoGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ acInfoGen.setStartDate(new ASN1GeneralizedTime(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ acInfoGen.setEndDate(new ASN1GeneralizedTime(date));
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ acInfoGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * add an attribute
+ */
+ public void addAttribute(
+ X509Attribute attribute)
+ {
+ acInfoGen.addAttribute(Attribute.getInstance(attribute.toASN1Object()));
+ }
+
+ public void setIssuerUniqueId(
+ boolean[] iui)
+ {
+ // [TODO] convert boolean array to bit string
+ //acInfoGen.setIssuerUniqueID(iui);
+ throw new RuntimeException("not implemented (yet)");
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag
+ * @throws IOException
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ throws IOException
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509AttributeCertificate generateCertificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateCertificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ * @deprecated use generate()
+ */
+ public X509AttributeCertificate generateCertificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception creating certificate: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509AttributeCertificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, SignatureException, InvalidKeyException, NoSuchAlgorithmException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ */
+ public X509AttributeCertificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (!extGenerator.isEmpty())
+ {
+ acInfoGen.setExtensions(extGenerator.generate());
+ }
+
+ AttributeCertificateInfo acInfo = acInfoGen.generateAttributeCertificateInfo();
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(acInfo);
+ v.add(sigAlgId);
+
+ try
+ {
+ v.add(new DERBitString(X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, acInfo)));
+
+ return new X509V2AttributeCertificate(new AttributeCertificate(new DERSequence(v)));
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("constructed invalid certificate", e);
+ }
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2CRLGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2CRLGenerator.java
new file mode 100644
index 000000000..4da0b8e09
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V2CRLGenerator.java
@@ -0,0 +1,451 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V2TBSCertListGenerator;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.X509CRLObject;
+
+/**
+ * class to produce an X.509 Version 2 CRL.
+ * @deprecated use org.spongycastle.cert.X509v2CRLBuilder.
+ */
+public class X509V2CRLGenerator
+{
+ private V2TBSCertListGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V2CRLGenerator()
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X500Principal issuer)
+ {
+ try
+ {
+ tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setThisUpdate(
+ Date date)
+ {
+ tbsGen.setThisUpdate(new Time(date));
+ }
+
+ public void setNextUpdate(
+ Date date)
+ {
+ tbsGen.setNextUpdate(new Time(date));
+ }
+
+ /**
+ * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise
+ * or 0 if CRLReason is not to be used
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason);
+ }
+
+ /**
+ * Add a CRL entry with an Invalidity Date extension as well as a CRLReason extension.
+ * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise
+ * or 0 if CRLReason is not to be used
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason, Date invalidityDate)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason, new ASN1GeneralizedTime(invalidityDate));
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, X509Extensions extensions)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), Extensions.getInstance(extensions));
+ }
+
+ /**
+ * Add the CRLEntry objects contained in a previous CRL.
+ *
+ * @param other the X509CRL to source the other entries from.
+ */
+ public void addCRL(X509CRL other)
+ throws CRLException
+ {
+ Set revocations = other.getRevokedCertificates();
+
+ if (revocations != null)
+ {
+ Iterator it = revocations.iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntry entry = (X509CRLEntry)it.next();
+
+ ASN1InputStream aIn = new ASN1InputStream(entry.getEncoded());
+
+ try
+ {
+ tbsGen.addCRLEntry(ASN1Sequence.getInstance(aIn.readObject()));
+ }
+ catch (IOException e)
+ {
+ throw new CRLException("exception processing encoding of CRL: " + e.toString());
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509CRL(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider "SC" and an user defined SecureRandom object as
+ * source of randomness.
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509CRL(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509CRL(key, provider, null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509CRL generate(
+ PrivateKey key)
+ throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider and an user defined SecureRandom object as
+ * source of randomness.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertList tbsCrl = generateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCRLException("cannot generate CRL encoding", e);
+ }
+
+ return generateJcaObject(tbsCrl, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the passed in provider for the signing.
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ String provider)
+ throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertList tbsCrl = generateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCRLException("cannot generate CRL encoding", e);
+ }
+
+ return generateJcaObject(tbsCrl, signature);
+ }
+
+ private TBSCertList generateCertList()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertList();
+ }
+
+ private X509CRL generateJcaObject(TBSCertList tbsCrl, byte[] signature)
+ throws CRLException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCrl);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CRLObject(new CertificateList(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+
+ private static class ExtCRLException
+ extends CRLException
+ {
+ Throwable cause;
+
+ ExtCRLException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V3CertificateGenerator.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V3CertificateGenerator.java
new file mode 100644
index 000000000..7ec1455b4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/X509V3CertificateGenerator.java
@@ -0,0 +1,527 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V3TBSCertificateGenerator;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.X509CertificateObject;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ * @deprecated use org.spongycastle.cert.X509v3CertificateBuilder.
+ */
+public class X509V3CertificateGenerator
+{
+ private V3TBSCertificateGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V3CertificateGenerator()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X500Principal issuer)
+ {
+ try
+ {
+ tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X500Principal subject)
+ {
+ try
+ {
+ tbsGen.setSubject(new X509Principal(subject.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo.getInstance(new ASN1InputStream(key.getEncoded()).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * Set the subject unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setSubjectUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setSubjectUniqueID(booleanToBitString(uniqueID));
+ }
+
+ /**
+ * Set the issuer unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setIssuerUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setIssuerUniqueID(booleanToBitString(uniqueID));
+ }
+
+ private DERBitString booleanToBitString(boolean[] id)
+ {
+ byte[] bytes = new byte[(id.length + 7) / 8];
+
+ for (int i = 0; i != id.length; i++)
+ {
+ bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0;
+ }
+
+ int pad = id.length % 8;
+
+ if (pad == 0)
+ {
+ return new DERBitString(bytes);
+ }
+ else
+ {
+ return new DERBitString(bytes, 8 - pad);
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ String oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extValue = cert.getExtensionValue(oid);
+
+ if (extValue == null)
+ {
+ throw new CertificateParsingException("extension " + oid + " not present");
+ }
+
+ try
+ {
+ ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue);
+
+ this.addExtension(oid, critical, value);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateParsingException(e.toString());
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ this.copyAndAddExtension(oid.getId(), critical, cert);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC", and the passed in source of randomness
+ * (if required).
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider, and the passed in source of randomness
+ * (if required).
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private TBSCertificate generateTbsCert()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertificate();
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateParsingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/examples/AttrCertExample.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/examples/AttrCertExample.java
new file mode 100644
index 000000000..28f065cef
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/examples/AttrCertExample.java
@@ -0,0 +1,314 @@
+package org.spongycastle.x509.examples;
+
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.x509.AttributeCertificateHolder;
+import org.spongycastle.x509.AttributeCertificateIssuer;
+import org.spongycastle.x509.X509Attribute;
+import org.spongycastle.x509.X509V1CertificateGenerator;
+import org.spongycastle.x509.X509V2AttributeCertificate;
+import org.spongycastle.x509.X509V2AttributeCertificateGenerator;
+import org.spongycastle.x509.X509V3CertificateGenerator;
+
+/**
+ * A simple example that generates an attribute certificate.
+ */
+public class AttrCertExample
+{
+ static X509V1CertificateGenerator v1CertGen = new X509V1CertificateGenerator();
+ static X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
+
+ /**
+ * we generate the AC issuer's certificate
+ */
+ public static X509Certificate createAcIssuerCert(
+ PublicKey pubKey,
+ PrivateKey privKey)
+ throws Exception
+ {
+ //
+ // signers name
+ //
+ String issuer = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+ //
+ // subjects name - the same as we are self signed.
+ //
+ String subject = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+ //
+ // create the certificate - version 1
+ //
+
+ v1CertGen.setSerialNumber(BigInteger.valueOf(10));
+ v1CertGen.setIssuerDN(new X509Principal(issuer));
+ v1CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
+ v1CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)));
+ v1CertGen.setSubjectDN(new X509Principal(subject));
+ v1CertGen.setPublicKey(pubKey);
+ v1CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ X509Certificate cert = v1CertGen.generate(privKey);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ return cert;
+ }
+
+ /**
+ * we generate a certificate signed by our CA's intermediate certficate
+ */
+ public static X509Certificate createClientCert(
+ PublicKey pubKey,
+ PrivateKey caPrivKey,
+ PublicKey caPubKey)
+ throws Exception
+ {
+ //
+ // issuer
+ //
+ String issuer = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+ //
+ // subjects name table.
+ //
+ Hashtable attrs = new Hashtable();
+ Vector order = new Vector();
+
+ attrs.put(X509Principal.C, "AU");
+ attrs.put(X509Principal.O, "The Legion of the Bouncy Castle");
+ attrs.put(X509Principal.L, "Melbourne");
+ attrs.put(X509Principal.CN, "Eric H. Echidna");
+ attrs.put(X509Principal.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ order.addElement(X509Principal.C);
+ order.addElement(X509Principal.O);
+ order.addElement(X509Principal.L);
+ order.addElement(X509Principal.CN);
+ order.addElement(X509Principal.EmailAddress);
+
+ //
+ // create the certificate - version 3
+ //
+ v3CertGen.reset();
+
+ v3CertGen.setSerialNumber(BigInteger.valueOf(20));
+ v3CertGen.setIssuerDN(new X509Principal(issuer));
+ v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
+ v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)));
+ v3CertGen.setSubjectDN(new X509Principal(order, attrs));
+ v3CertGen.setPublicKey(pubKey);
+ v3CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ //
+ // add the extensions
+ //
+
+ v3CertGen.addExtension(
+ MiscObjectIdentifiers.netscapeCertType,
+ false,
+ new NetscapeCertType(NetscapeCertType.objectSigning | NetscapeCertType.smime));
+
+ X509Certificate cert = v3CertGen.generate(caPrivKey);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(caPubKey);
+
+ return cert;
+ }
+
+ public static void main(String args[])
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ //
+ // personal keys
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16),
+ new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+ new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+ new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+ new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+ new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+ new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+ //
+ // ca keys
+ //
+ RSAPublicKeySpec caPubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeySpec caPrivKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+ new BigInteger("11", 16),
+ new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16),
+ new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16),
+ new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16),
+ new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16),
+ new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16),
+ new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16));
+
+ //
+ // set up the keys
+ //
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+ PrivateKey caPrivKey = fact.generatePrivate(caPrivKeySpec);
+ PublicKey caPubKey = fact.generatePublic(caPubKeySpec);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // note in this case we are using the CA certificate for both the client cetificate
+ // and the attribute certificate. This is to make the vcode simpler to read, in practice
+ // the CA for the attribute certificate should be different to that of the client certificate
+ //
+ X509Certificate caCert = createAcIssuerCert(caPubKey, caPrivKey);
+ X509Certificate clientCert = createClientCert(pubKey, caPrivKey, caPubKey);
+
+ // Instantiate a new AC generator
+ X509V2AttributeCertificateGenerator acGen = new X509V2AttributeCertificateGenerator();
+
+ acGen.reset();
+
+ //
+ // Holder: here we use the IssuerSerial form
+ //
+ acGen.setHolder(new AttributeCertificateHolder(clientCert));
+
+ // set the Issuer
+ acGen.setIssuer(new AttributeCertificateIssuer(caCert.getSubjectX500Principal()));
+
+ //
+ // serial number (as it's an example we don't have to keep track of the
+ // serials anyway
+ //
+ acGen.setSerialNumber(new BigInteger("1"));
+
+ // not Before
+ acGen.setNotBefore(new Date(System.currentTimeMillis() - 50000));
+
+ // not After
+ acGen.setNotAfter(new Date(System.currentTimeMillis() + 50000));
+
+ // signature Algorithmus
+ acGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ // the actual attributes
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+ X509Attribute attributes = new X509Attribute("2.5.24.72",
+ new DERSequence(roleSyntax));
+
+ acGen.addAttribute(attributes);
+
+ // finally create the AC
+ X509V2AttributeCertificate att = (X509V2AttributeCertificate)acGen
+ .generate(caPrivKey, "SC");
+
+ //
+ // starting here, we parse the newly generated AC
+ //
+
+ // Holder
+
+ AttributeCertificateHolder h = att.getHolder();
+ if (h.match(clientCert))
+ {
+ if (h.getEntityNames() != null)
+ {
+ System.out.println(h.getEntityNames().length + " entity names found");
+ }
+ if (h.getIssuer() != null)
+ {
+ System.out.println(h.getIssuer().length + " issuer names found, serial number " + h.getSerialNumber());
+ }
+ System.out.println("Matches original client x509 cert");
+ }
+
+ // Issuer
+
+ AttributeCertificateIssuer issuer = att.getIssuer();
+ if (issuer.match(caCert))
+ {
+ if (issuer.getPrincipals() != null)
+ {
+ System.out.println(issuer.getPrincipals().length + " entity names found");
+ }
+ System.out.println("Matches original ca x509 cert");
+ }
+
+ // Dates
+ System.out.println("valid not before: " + att.getNotBefore());
+ System.out.println("valid not before: " + att.getNotAfter());
+
+ // check the dates, an exception is thrown in checkValidity()...
+
+ try
+ {
+ att.checkValidity();
+ att.checkValidity(new Date());
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+
+ // verify
+
+ try
+ {
+ att.verify(caPubKey, "SC");
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+
+ // Attribute
+ X509Attribute[] attribs = att.getAttributes();
+ System.out.println("cert has " + attribs.length + " attributes:");
+ for (int i = 0; i < attribs.length; i++)
+ {
+ X509Attribute a = attribs[i];
+ System.out.println("OID: " + a.getOID());
+
+ // currently we only check for the presence of a 'RoleSyntax' attribute
+
+ if (a.getOID().equals("2.5.24.72"))
+ {
+ System.out.println("rolesyntax read from cert!");
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/AuthorityKeyIdentifierStructure.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/AuthorityKeyIdentifierStructure.java
new file mode 100644
index 000000000..bb1380220
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/AuthorityKeyIdentifierStructure.java
@@ -0,0 +1,152 @@
+package org.spongycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.PublicKey;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.PrincipalUtil;
+
+/**
+ * A high level authority key identifier.
+ * @deprecated use JcaX509ExtensionUtils and AuthorityKeyIdentifier.getInstance()
+ */
+public class AuthorityKeyIdentifierStructure
+ extends AuthorityKeyIdentifier
+{
+ /**
+ * Constructor which will take the byte[] returned from getExtensionValue()
+ *
+ * @param encodedValue a DER octet encoded string with the extension structure in it.
+ * @throws IOException on parsing errors.
+ */
+ public AuthorityKeyIdentifierStructure(
+ byte[] encodedValue)
+ throws IOException
+ {
+ super((ASN1Sequence)X509ExtensionUtil.fromExtensionValue(encodedValue));
+ }
+
+ /**
+ * Constructor which will take an extension
+ *
+ * @param extension a X509Extension object containing an AuthorityKeyIdentifier.
+ * @deprecated use constructor that takes Extension
+ */
+ public AuthorityKeyIdentifierStructure(
+ X509Extension extension)
+ {
+ super((ASN1Sequence)extension.getParsedValue());
+ }
+
+ /**
+ * Constructor which will take an extension
+ *
+ * @param extension a X509Extension object containing an AuthorityKeyIdentifier.
+ */
+ public AuthorityKeyIdentifierStructure(
+ Extension extension)
+ {
+ super((ASN1Sequence)extension.getParsedValue());
+ }
+
+ private static ASN1Sequence fromCertificate(
+ X509Certificate certificate)
+ throws CertificateParsingException
+ {
+ try
+ {
+ if (certificate.getVersion() != 3)
+ {
+ GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate));
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)new ASN1InputStream(certificate.getPublicKey().getEncoded()).readObject());
+
+ return (ASN1Sequence)new AuthorityKeyIdentifier(
+ info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+ }
+ else
+ {
+ GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate));
+
+ byte[] ext = certificate.getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId());
+
+ if (ext != null)
+ {
+ ASN1OctetString str = (ASN1OctetString)X509ExtensionUtil.fromExtensionValue(ext);
+
+ return (ASN1Sequence)new AuthorityKeyIdentifier(
+ str.getOctets(), new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+ }
+ else
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)new ASN1InputStream(certificate.getPublicKey().getEncoded()).readObject());
+
+ return (ASN1Sequence)new AuthorityKeyIdentifier(
+ info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("Exception extracting certificate details: " + e.toString());
+ }
+ }
+
+ private static ASN1Sequence fromKey(
+ PublicKey pubKey)
+ throws InvalidKeyException
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)new ASN1InputStream(pubKey.getEncoded()).readObject());
+
+ return (ASN1Sequence)new AuthorityKeyIdentifier(info).toASN1Object();
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't process key: " + e);
+ }
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using the passed in certificate's public
+ * key, issuer and serial number.
+ *
+ * @param certificate the certificate providing the information.
+ * @throws CertificateParsingException if there is a problem processing the certificate
+ */
+ public AuthorityKeyIdentifierStructure(
+ X509Certificate certificate)
+ throws CertificateParsingException
+ {
+ super(fromCertificate(certificate));
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using just the hash of the
+ * public key.
+ *
+ * @param pubKey the key to generate the hash from.
+ * @throws InvalidKeyException if there is a problem using the key.
+ */
+ public AuthorityKeyIdentifierStructure(
+ PublicKey pubKey)
+ throws InvalidKeyException
+ {
+ super(fromKey(pubKey));
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/SubjectKeyIdentifierStructure.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/SubjectKeyIdentifierStructure.java
new file mode 100644
index 000000000..bf85ab02f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/SubjectKeyIdentifierStructure.java
@@ -0,0 +1,53 @@
+package org.spongycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * A high level subject key identifier.
+ * @deprecated use JcaX509ExtensionUtils andSubjectKeyIdentifier.getInstance()
+ */
+public class SubjectKeyIdentifierStructure
+ extends SubjectKeyIdentifier
+{
+ /**
+ * Constructor which will take the byte[] returned from getExtensionValue()
+ *
+ * @param encodedValue a DER octet encoded string with the extension structure in it.
+ * @throws IOException on parsing errors.
+ */
+ public SubjectKeyIdentifierStructure(
+ byte[] encodedValue)
+ throws IOException
+ {
+ super((ASN1OctetString)X509ExtensionUtil.fromExtensionValue(encodedValue));
+ }
+
+ private static ASN1OctetString fromPublicKey(
+ PublicKey pubKey)
+ throws InvalidKeyException
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+
+ return (ASN1OctetString)(new SubjectKeyIdentifier(info).toASN1Object());
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("Exception extracting key details: " + e.toString());
+ }
+ }
+
+ public SubjectKeyIdentifierStructure(
+ PublicKey pubKey)
+ throws InvalidKeyException
+ {
+ super(fromPublicKey(pubKey));
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/X509ExtensionUtil.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/X509ExtensionUtil.java
new file mode 100644
index 000000000..4a6a93d67
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/extension/X509ExtensionUtil.java
@@ -0,0 +1,101 @@
+package org.spongycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.util.Integers;
+
+
+public class X509ExtensionUtil
+{
+ public static ASN1Primitive fromExtensionValue(
+ byte[] encodedValue)
+ throws IOException
+ {
+ ASN1OctetString octs = (ASN1OctetString)ASN1Primitive.fromByteArray(encodedValue);
+
+ return ASN1Primitive.fromByteArray(octs.getOctets());
+ }
+
+ public static Collection getIssuerAlternativeNames(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extVal = cert.getExtensionValue(X509Extension.issuerAlternativeName.getId());
+
+ return getAlternativeNames(extVal);
+ }
+
+ public static Collection getSubjectAlternativeNames(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extVal = cert.getExtensionValue(X509Extension.subjectAlternativeName.getId());
+
+ return getAlternativeNames(extVal);
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return Collections.EMPTY_LIST;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = DERSequence.getInstance(fromExtensionValue(extVal)).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ list.add(Integers.valueOf(genName.getTagNo()));
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getName().toASN1Primitive());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ list.add(DEROctetString.getInstance(genName.getName()).getOctets());
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(list);
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/LDAPStoreHelper.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/LDAPStoreHelper.java
new file mode 100644
index 000000000..6692c27e8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/LDAPStoreHelper.java
@@ -0,0 +1,1116 @@
+package org.spongycastle.x509.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.sql.Date;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificatePair;
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.jce.provider.X509AttrCertParser;
+import org.spongycastle.jce.provider.X509CRLParser;
+import org.spongycastle.jce.provider.X509CertPairParser;
+import org.spongycastle.jce.provider.X509CertParser;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertPairStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+import org.spongycastle.x509.X509CertificatePair;
+
+/**
+ * This is a general purpose implementation to get X.509 certificates, CRLs,
+ * attribute certificates and cross certificates from a LDAP location.
+ * <p/>
+ * At first a search is performed in the ldap*AttributeNames of the
+ * {@link org.spongycastle.jce.X509LDAPCertStoreParameters} with the given
+ * information of the subject (for all kind of certificates) or issuer (for
+ * CRLs), respectively, if a {@link org.spongycastle.x509.X509CertStoreSelector} or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} is given with that
+ * details.
+ * <p/>
+ * For the used schemes see:
+ * <ul>
+ * <li><a href="http://www.ietf.org/rfc/rfc2587.txt">RFC 2587</a>
+ * <li><a
+ * href="http://www3.ietf.org/proceedings/01mar/I-D/pkix-ldap-schema-01.txt">Internet
+ * X.509 Public Key Infrastructure Additional LDAP Schema for PKIs and PMIs</a>
+ * </ul>
+ */
+public class LDAPStoreHelper
+{
+
+ // TODO: cache results
+
+ private X509LDAPCertStoreParameters params;
+
+ public LDAPStoreHelper(X509LDAPCertStoreParameters params)
+ {
+ this.params = params;
+ }
+
+ /**
+ * Initial Context Factory.
+ */
+ private static String LDAP_PROVIDER = "com.sun.jndi.ldap.LdapCtxFactory";
+
+ /**
+ * Processing referrals..
+ */
+ private static String REFERRALS_IGNORE = "ignore";
+
+ /**
+ * Security level to be used for LDAP connections.
+ */
+ private static final String SEARCH_SECURITY_LEVEL = "none";
+
+ /**
+ * Package Prefix for loading URL context factories.
+ */
+ private static final String URL_CONTEXT_PREFIX = "com.sun.jndi.url";
+
+ private DirContext connectLDAP() throws NamingException
+ {
+ Properties props = new Properties();
+ props.setProperty(Context.INITIAL_CONTEXT_FACTORY, LDAP_PROVIDER);
+ props.setProperty(Context.BATCHSIZE, "0");
+
+ props.setProperty(Context.PROVIDER_URL, params.getLdapURL());
+ props.setProperty(Context.URL_PKG_PREFIXES, URL_CONTEXT_PREFIX);
+ props.setProperty(Context.REFERRAL, REFERRALS_IGNORE);
+ props.setProperty(Context.SECURITY_AUTHENTICATION,
+ SEARCH_SECURITY_LEVEL);
+
+ DirContext ctx = new InitialDirContext(props);
+ return ctx;
+ }
+
+ private String parseDN(String subject, String dNAttributeName)
+ {
+ String temp = subject;
+ int begin = temp.toLowerCase().indexOf(
+ dNAttributeName.toLowerCase() + "=");
+ if (begin == -1)
+ {
+ return "";
+ }
+ temp = temp.substring(begin + dNAttributeName.length());
+ int end = temp.indexOf(',');
+ if (end == -1)
+ {
+ end = temp.length();
+ }
+ while (temp.charAt(end - 1) == '\\')
+ {
+ end = temp.indexOf(',', end + 1);
+ if (end == -1)
+ {
+ end = temp.length();
+ }
+ }
+ temp = temp.substring(0, end);
+ begin = temp.indexOf('=');
+ temp = temp.substring(begin + 1);
+ if (temp.charAt(0) == ' ')
+ {
+ temp = temp.substring(1);
+ }
+ if (temp.startsWith("\""))
+ {
+ temp = temp.substring(1);
+ }
+ if (temp.endsWith("\""))
+ {
+ temp = temp.substring(0, temp.length() - 1);
+ }
+ return temp;
+ }
+
+ private Set createCerts(List list, X509CertStoreSelector xselector)
+ throws StoreException
+ {
+ Set certSet = new HashSet();
+
+ Iterator it = list.iterator();
+ X509CertParser parser = new X509CertParser();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509Certificate cert = (X509Certificate)parser
+ .engineRead();
+ if (xselector.match((Object)cert))
+ {
+ certSet.add(cert);
+ }
+
+ }
+ catch (Exception e)
+ {
+
+ }
+ }
+
+ return certSet;
+ }
+
+ /**
+ * Can use the subject and serial and the subject and serialNumber of the
+ * certificate of the given of the X509CertStoreSelector. If a certificate
+ * for checking is given this has higher precedence.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the certificates in the LDAP
+ * directory.
+ * @param attrNames Attribute names in teh LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded certificates.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List certSubjectSerialSearch(X509CertStoreSelector xselector,
+ String[] attrs, String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ // TODO: support also subjectAltNames?
+ List list = new ArrayList();
+
+ String subject = null;
+ String serial = null;
+
+ subject = getSubjectAsString(xselector);
+
+ if (xselector.getSerialNumber() != null)
+ {
+ serial = xselector.getSerialNumber().toString();
+ }
+ if (xselector.getCertificate() != null)
+ {
+ subject = xselector.getCertificate().getSubjectX500Principal().getName("RFC1779");
+ serial = xselector.getCertificate().getSerialNumber().toString();
+ }
+
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (serial != null && params.getSearchForSerialNumberIn() != null)
+ {
+ attrValue = serial;
+ list.addAll(search(
+ splitString(params.getSearchForSerialNumberIn()),
+ attrValue, attrs));
+ }
+ if (serial == null && subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+
+
+ /**
+ * Can use the subject of the forward certificate of the set certificate
+ * pair or the subject of the forward
+ * {@link org.spongycastle.x509.X509CertStoreSelector} of the given
+ * selector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded certificate pairs.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List crossCertificatePairSubjectSearch(
+ X509CertPairStoreSelector xselector, String[] attrs,
+ String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ // search for subject
+ String subject = null;
+
+ if (xselector.getForwardSelector() != null)
+ {
+ subject = getSubjectAsString(xselector.getForwardSelector());
+ }
+ if (xselector.getCertPair() != null)
+ {
+ if (xselector.getCertPair().getForward() != null)
+ {
+ subject = xselector.getCertPair().getForward()
+ .getSubjectX500Principal().getName("RFC1779");
+ }
+ }
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Can use the entityName of the holder of the attribute certificate, the
+ * serialNumber of attribute certificate and the serialNumber of the
+ * associated certificate of the given of the X509AttributeCertSelector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded attribute certificates.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List attrCertSubjectSerialSearch(
+ X509AttributeCertStoreSelector xselector, String[] attrs,
+ String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ // search for serialNumber of associated cert,
+ // serialNumber of the attribute certificate or DN in the entityName
+ // of the holder
+
+ String subject = null;
+ String serial = null;
+
+ Collection serials = new HashSet();
+ Principal principals[] = null;
+ if (xselector.getHolder() != null)
+ {
+ // serialNumber of associated cert
+ if (xselector.getHolder().getSerialNumber() != null)
+ {
+ serials.add(xselector.getHolder().getSerialNumber()
+ .toString());
+ }
+ // DN in the entityName of the holder
+ if (xselector.getHolder().getEntityNames() != null)
+ {
+ principals = xselector.getHolder().getEntityNames();
+ }
+ }
+
+ if (xselector.getAttributeCert() != null)
+ {
+ if (xselector.getAttributeCert().getHolder().getEntityNames() != null)
+ {
+ principals = xselector.getAttributeCert().getHolder()
+ .getEntityNames();
+ }
+ // serialNumber of the attribute certificate
+ serials.add(xselector.getAttributeCert().getSerialNumber()
+ .toString());
+ }
+ if (principals != null)
+ {
+ // only first should be relevant
+ if (principals[0] instanceof X500Principal)
+ {
+ subject = ((X500Principal)principals[0])
+ .getName("RFC1779");
+ }
+ else
+ {
+ // strange ...
+ subject = principals[0].getName();
+ }
+ }
+ if (xselector.getSerialNumber() != null)
+ {
+ serials.add(xselector.getSerialNumber().toString());
+ }
+
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (serials.size() > 0
+ && params.getSearchForSerialNumberIn() != null)
+ {
+ Iterator it = serials.iterator();
+ while (it.hasNext())
+ {
+ serial = (String)it.next();
+ list.addAll(search(splitString(params.getSearchForSerialNumberIn()), serial, attrs));
+ }
+ }
+ if (serials.size() == 0 && subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Can use the issuer of the given of the X509CRLStoreSelector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param issuerAttributeNames Issuer attribute names (like "CN", "O", "OU") to use to search
+ * in the LDAP directory
+ * @return A list of found DER encoded CRLs.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List cRLIssuerSearch(X509CRLStoreSelector xselector,
+ String[] attrs, String attrNames[], String issuerAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ String issuer = null;
+ Collection issuers = new HashSet();
+ if (xselector.getIssuers() != null)
+ {
+ issuers.addAll(xselector.getIssuers());
+ }
+ if (xselector.getCertificateChecking() != null)
+ {
+ issuers.add(getCertificateIssuer(xselector.getCertificateChecking()));
+ }
+ if (xselector.getAttrCertificateChecking() != null)
+ {
+ Principal principals[] = xselector.getAttrCertificateChecking().getIssuer().getPrincipals();
+ for (int i=0; i<principals.length; i++)
+ {
+ if (principals[i] instanceof X500Principal)
+ {
+ issuers.add(principals[i]);
+ }
+ }
+ }
+ Iterator it = issuers.iterator();
+ while (it.hasNext())
+ {
+ issuer = ((X500Principal)it.next()).getName("RFC1779");
+ String attrValue = null;
+
+ for (int i = 0; i < issuerAttributeNames.length; i++)
+ {
+ attrValue = parseDN(issuer, issuerAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (issuer == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Returns a <code>List</code> of encodings of the certificates, attribute
+ * certificates, CRL or certificate pairs.
+ *
+ * @param attributeNames The attribute names to look for in the LDAP.
+ * @param attributeValue The value the attribute name must have.
+ * @param attrs The attributes in the LDAP which hold the certificate,
+ * attribute certificate, certificate pair or CRL in a found
+ * entry.
+ * @return A <code>List</code> of byte arrays with the encodings.
+ * @throws StoreException if an error occurs getting the results from the LDAP
+ * directory.
+ */
+ private List search(String attributeNames[], String attributeValue,
+ String[] attrs) throws StoreException
+ {
+ String filter = null;
+ if (attributeNames == null)
+ {
+ filter = null;
+ }
+ else
+ {
+ filter = "";
+ if (attributeValue.equals("**"))
+ {
+ attributeValue = "*";
+ }
+ for (int i = 0; i < attributeNames.length; i++)
+ {
+ filter += "(" + attributeNames[i] + "=" + attributeValue + ")";
+ }
+ filter = "(|" + filter + ")";
+ }
+ String filter2 = "";
+ for (int i = 0; i < attrs.length; i++)
+ {
+ filter2 += "(" + attrs[i] + "=*)";
+ }
+ filter2 = "(|" + filter2 + ")";
+
+ String filter3 = "(&" + filter + "" + filter2 + ")";
+ if (filter == null)
+ {
+ filter3 = filter2;
+ }
+ List list;
+ list = getFromCache(filter3);
+ if (list != null)
+ {
+ return list;
+ }
+ DirContext ctx = null;
+ list = new ArrayList();
+ try
+ {
+
+ ctx = connectLDAP();
+
+ SearchControls constraints = new SearchControls();
+ constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ constraints.setCountLimit(0);
+ constraints.setReturningAttributes(attrs);
+ NamingEnumeration results = ctx.search(params.getBaseDN(), filter3,
+ constraints);
+ while (results.hasMoreElements())
+ {
+ SearchResult sr = (SearchResult)results.next();
+ NamingEnumeration enumeration = ((Attribute)(sr
+ .getAttributes().getAll().next())).getAll();
+ while (enumeration.hasMore())
+ {
+ list.add(enumeration.next());
+ }
+ }
+ addToCache(filter3, list);
+ }
+ catch (NamingException e)
+ {
+ // skip exception, unfortunately if an attribute type is not
+ // supported an exception is thrown
+
+ }
+ finally
+ {
+ try
+ {
+ if (null != ctx)
+ {
+ ctx.close();
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ return list;
+ }
+
+ private Set createCRLs(List list, X509CRLStoreSelector xselector)
+ throws StoreException
+ {
+ Set crlSet = new HashSet();
+
+ X509CRLParser parser = new X509CRLParser();
+ Iterator it = list.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509CRL crl = (X509CRL)parser.engineRead();
+ if (xselector.match((Object)crl))
+ {
+ crlSet.add(crl);
+ }
+ }
+ catch (StreamParsingException e)
+ {
+
+ }
+ }
+
+ return crlSet;
+ }
+
+ private Set createCrossCertificatePairs(List list,
+ X509CertPairStoreSelector xselector) throws StoreException
+ {
+ Set certPairSet = new HashSet();
+
+ int i = 0;
+ while (i < list.size())
+ {
+ X509CertificatePair pair;
+ try
+ {
+ // first try to decode it as certificate pair
+ try
+ {
+ X509CertPairParser parser = new X509CertPairParser();
+ parser.engineInit(new ByteArrayInputStream(
+ (byte[])list.get(i)));
+ pair = (X509CertificatePair)parser.engineRead();
+ }
+ catch (StreamParsingException e)
+ {
+ // now try it to construct it the forward and reverse
+ // certificate
+ byte[] forward = (byte[])list.get(i);
+ byte[] reverse = (byte[])list.get(i + 1);
+ pair = new X509CertificatePair(new CertificatePair(
+ Certificate
+ .getInstance(new ASN1InputStream(
+ forward).readObject()),
+ Certificate
+ .getInstance(new ASN1InputStream(
+ reverse).readObject())));
+ i++;
+ }
+ if (xselector.match((Object)pair))
+ {
+ certPairSet.add(pair);
+ }
+ }
+ catch (CertificateParsingException e)
+ {
+ // try next
+ }
+ catch (IOException e)
+ {
+ // try next
+ }
+ i++;
+ }
+
+ return certPairSet;
+ }
+
+ private Set createAttributeCertificates(List list,
+ X509AttributeCertStoreSelector xselector) throws StoreException
+ {
+ Set certSet = new HashSet();
+
+ Iterator it = list.iterator();
+ X509AttrCertParser parser = new X509AttrCertParser();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509AttributeCertificate cert = (X509AttributeCertificate)parser
+ .engineRead();
+ if (xselector.match((Object)cert))
+ {
+ certSet.add(cert);
+ }
+ }
+ catch (StreamParsingException e)
+ {
+
+ }
+ }
+
+ return certSet;
+ }
+
+ /**
+ * Returns the CRLs for issued certificates for other CAs matching the given
+ * selector. <br>
+ * The authorityRevocationList attribute includes revocation information
+ * regarding certificates issued to other CAs.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs
+ * @throws StoreException
+ */
+ public Collection getAuthorityRevocationLists(X509CRLStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getAuthorityRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAuthorityRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAuthorityRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the revocation list for revoked attribute certificates.
+ * <p/>
+ * The attributeCertificateRevocationList holds a list of attribute
+ * certificates that have been revoked.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getAttributeCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params
+ .getAttributeCertificateRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeCertificateRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAttributeCertificateRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the revocation list for revoked attribute certificates for an
+ * attribute authority
+ * <p/>
+ * The attributeAuthorityList holds a list of AA certificates that have been
+ * revoked.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs
+ * @throws StoreException
+ */
+ public Collection getAttributeAuthorityRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeAuthorityRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeAuthorityRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAttributeAuthorityRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns cross certificate pairs.
+ *
+ * @param selector The selector to use to find the cross certificates.
+ * @return A possible empty collection with {@link X509CertificatePair}s
+ * @throws StoreException
+ */
+ public Collection getCrossCertificatePairs(
+ X509CertPairStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getCrossCertificateAttribute());
+ String attrNames[] = splitString(params.getLdapCrossCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getCrossCertificateSubjectAttributeName());
+ List list = crossCertificatePairSubjectSearch(selector, attrs,
+ attrNames, subjectAttributeNames);
+ Set resultSet = createCrossCertificatePairs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptyCertselector = new X509CertStoreSelector();
+ X509CertPairStoreSelector emptySelector = new X509CertPairStoreSelector();
+
+ emptySelector.setForwardSelector(emptyCertselector);
+ emptySelector.setReverseSelector(emptyCertselector);
+ list = crossCertificatePairSubjectSearch(emptySelector, attrs,
+ attrNames, subjectAttributeNames);
+ resultSet.addAll(createCrossCertificatePairs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns end certificates.
+ * <p/>
+ * The attributeDescriptorCertificate is self signed by a source of
+ * authority and holds a description of the privilege and its delegation
+ * rules.
+ *
+ * @param selector The selector to find the certificates.
+ * @return A possible empty collection with certificates.
+ * @throws StoreException
+ */
+ public Collection getUserCertificates(X509CertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getUserCertificateAttribute());
+ String attrNames[] = splitString(params.getLdapUserCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getUserCertificateSubjectAttributeName());
+
+ List list = certSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createCerts(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptySelector = new X509CertStoreSelector();
+ list = certSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createCerts(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns attribute certificates for an attribute authority
+ * <p/>
+ * The aAcertificate holds the privileges of an attribute authority.
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAACertificates(X509AttributeCertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getAACertificateAttribute());
+ String attrNames[] = splitString(params.getLdapAACertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params.getAACertificateSubjectAttributeName());
+
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns an attribute certificate for an authority
+ * <p/>
+ * The attributeDescriptorCertificate is self signed by a source of
+ * authority and holds a description of the privilege and its delegation
+ * rules.
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAttributeDescriptorCertificates(
+ X509AttributeCertStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeDescriptorCertificateAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeDescriptorCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getAttributeDescriptorCertificateSubjectAttributeName());
+
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns CA certificates.
+ * <p/>
+ * The cACertificate attribute of a CA's directory entry shall be used to
+ * store self-issued certificates (if any) and certificates issued to this
+ * CA by CAs in the same realm as this CA.
+ *
+ * @param selector The selector to find the certificates.
+ * @return A possible empty collection with certificates.
+ * @throws StoreException
+ */
+ public Collection getCACertificates(X509CertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getCACertificateAttribute());
+ String attrNames[] = splitString(params.getLdapCACertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getCACertificateSubjectAttributeName());
+ List list = certSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createCerts(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptySelector = new X509CertStoreSelector();
+ list = certSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createCerts(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the delta revocation list for revoked certificates.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getDeltaCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getDeltaRevocationListAttribute());
+ String attrNames[] = splitString(params.getLdapDeltaRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getDeltaRevocationListIssuerAttributeName());
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns an attribute certificate for an user.
+ * <p/>
+ * The attributeCertificateAttribute holds the privileges of a user
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAttributeCertificateAttributes(
+ X509AttributeCertStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeCertificateAttributeAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeCertificateAttributeAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getAttributeCertificateAttributeSubjectAttributeName());
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns the certificate revocation lists for revoked certificates.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getCertificateRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapCertificateRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getCertificateRevocationListIssuerAttributeName());
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ private Map cacheMap = new HashMap(cacheSize);
+
+ private static int cacheSize = 32;
+
+ private static long lifeTime = 60 * 1000;
+
+ private synchronized void addToCache(String searchCriteria, List list)
+ {
+ Date now = new Date(System.currentTimeMillis());
+ List cacheEntry = new ArrayList();
+ cacheEntry.add(now);
+ cacheEntry.add(list);
+ if (cacheMap.containsKey(searchCriteria))
+ {
+ cacheMap.put(searchCriteria, cacheEntry);
+ }
+ else
+ {
+ if (cacheMap.size() >= cacheSize)
+ {
+ // replace oldest
+ Iterator it = cacheMap.entrySet().iterator();
+ long oldest = now.getTime();
+ Object replace = null;
+ while (it.hasNext())
+ {
+ Map.Entry entry = (Map.Entry)it.next();
+ long current = ((Date)((List)entry.getValue()).get(0))
+ .getTime();
+ if (current < oldest)
+ {
+ oldest = current;
+ replace = entry.getKey();
+ }
+ }
+ cacheMap.remove(replace);
+ }
+ cacheMap.put(searchCriteria, cacheEntry);
+ }
+ }
+
+ private List getFromCache(String searchCriteria)
+ {
+ List entry = (List)cacheMap.get(searchCriteria);
+ long now = System.currentTimeMillis();
+ if (entry != null)
+ {
+ // too old
+ if (((Date)entry.get(0)).getTime() < (now - lifeTime))
+ {
+ return null;
+ }
+ return (List)entry.get(1);
+ }
+ return null;
+ }
+
+ /*
+ * spilt string based on spaces
+ */
+ private String[] splitString(String str)
+ {
+ return str.split("\\s+");
+ }
+
+ private String getSubjectAsString(X509CertStoreSelector xselector)
+ {
+ try
+ {
+ byte[] encSubject = xselector.getSubjectAsBytes();
+ if (encSubject != null)
+ {
+ return new X500Principal(encSubject).getName("RFC1779");
+ }
+ }
+ catch (IOException e)
+ {
+ throw new StoreException("exception processing name: " + e.getMessage(), e);
+ }
+ return null;
+ }
+
+ private X500Principal getCertificateIssuer(X509Certificate cert)
+ {
+ return cert.getIssuerX500Principal();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/StreamParser.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/StreamParser.java
new file mode 100644
index 000000000..f0db6643e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/StreamParser.java
@@ -0,0 +1,10 @@
+package org.spongycastle.x509.util;
+
+import java.util.Collection;
+
+public interface StreamParser
+{
+ Object read() throws StreamParsingException;
+
+ Collection readAll() throws StreamParsingException;
+}
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/StreamParsingException.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/StreamParsingException.java
new file mode 100644
index 000000000..6d005e92e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/x509/util/StreamParsingException.java
@@ -0,0 +1,18 @@
+package org.spongycastle.x509.util;
+
+public class StreamParsingException
+ extends Exception
+{
+ Throwable _e;
+
+ public StreamParsingException(String message, Throwable e)
+ {
+ super(message);
+ _e = e;
+ }
+
+ public Throwable getCause()
+ {
+ return _e;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/examples/package.html b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/examples/package.html
new file mode 100644
index 000000000..96b319396
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/examples/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Example classes for use with the JCE.
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/interfaces/package.html b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/interfaces/package.html
new file mode 100644
index 000000000..bacde6c88
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/interfaces/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Interfaces for supporting Elliptic Curve Keys, El Gamal, and PKCS12 attributes.
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/package.html b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/package.html
new file mode 100644
index 000000000..52ef3bf64
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/package.html
@@ -0,0 +1,10 @@
+<html>
+<body bgcolor="#ffffff">
+Utility classes for use with the JCE.
+<p>
+The classes in this package support the generation of certificates and PKCS10 signing requests.
+<p>
+Note: the PKCS7 class is deprecated, for a fuller version of CMS see the cms package distributed
+with the BC mail API.
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/spec/package.html b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/spec/package.html
new file mode 100644
index 000000000..6f370577d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/jce/spec/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Parameter specifications for supporting El Gamal, and Elliptic Curve.
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/ocsp/package.html b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/ocsp/package.html
new file mode 100644
index 000000000..ca4f53182
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/ocsp/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Classes for dealing Online Certificate Status Protocol (OCSP) - RFC 2560.
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/examples/package.html b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/examples/package.html
new file mode 100644
index 000000000..6262157db
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/examples/package.html
@@ -0,0 +1,7 @@
+<html>
+<body bgcolor="#ffffff">
+<p>
+Examples for X.509 attribute certificates.
+<p>
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/extension/package.html b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/extension/package.html
new file mode 100644
index 000000000..abc2da578
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/extension/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Helper classes for dealing with common X.509 extensions.
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/package.html b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/package.html
new file mode 100644
index 000000000..b6b5298bc
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/javadoc/org/spongycastle/x509/package.html
@@ -0,0 +1,7 @@
+<html>
+<body bgcolor="#ffffff">
+<p>
+Classes for supporting the generation of X.509 certificates and X.509 attribute certificates.
+<p>
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
new file mode 100644
index 000000000..16fe1696a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
@@ -0,0 +1,280 @@
+package org.spongycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.Signature;
+import java.security.interfaces.DSAKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.NullDigest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+
+public class DSASigner
+ extends Signature
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+ private SecureRandom random;
+
+ protected DSASigner(
+ Digest digest,
+ DSA signer)
+ {
+ super("DSA");
+ this.digest = digest;
+ this.signer = signer;
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+// if (publicKey instanceof GOST3410Key)
+// {
+// param = GOST3410Util.generatePublicKeyParameter(publicKey);
+// }
+// else if (publicKey instanceof DSAKey)
+ if (publicKey instanceof DSAKey)
+ {
+ param = DSAUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof DSAKey)
+ {
+ param = DSAUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+// if (privateKey instanceof GOST3410Key)
+// {
+// param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+// }
+// else
+// {
+ param = DSAUtil.generatePrivateKeyParameter(privateKey);
+// }
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ digest.reset();
+ signer.init(true, param);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+
+ return derEncode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ sig = derDecode(sigBytes);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ private byte[] derEncode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ ASN1Integer[] rs = new ASN1Integer[]{ new ASN1Integer(r), new ASN1Integer(s) };
+ return new DERSequence(rs).getEncoded(ASN1Encoding.DER);
+ }
+
+ private BigInteger[] derDecode(
+ byte[] encoding)
+ throws IOException
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ return new BigInteger[]{
+ ((ASN1Integer)s.getObjectAt(0)).getValue(),
+ ((ASN1Integer)s.getObjectAt(1)).getValue()
+ };
+ }
+
+ static public class stdDSA
+ extends DSASigner
+ {
+ public stdDSA()
+ {
+ super(new SHA1Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class dsa224
+ extends DSASigner
+ {
+ public dsa224()
+ {
+ super(new SHA224Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class dsa256
+ extends DSASigner
+ {
+ public dsa256()
+ {
+ super(new SHA256Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class dsa384
+ extends DSASigner
+ {
+ public dsa384()
+ {
+ super(new SHA384Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class dsa512
+ extends DSASigner
+ {
+ public dsa512()
+ {
+ super(new SHA512Digest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+
+ static public class noneDSA
+ extends DSASigner
+ {
+ public noneDSA()
+ {
+ super(new NullDigest(), new org.spongycastle.crypto.signers.DSASigner());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
new file mode 100644
index 000000000..54b83de7e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
@@ -0,0 +1,221 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.ECGOST3410Signer;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.GOST3410Key;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.util.GOST3410Util;
+
+public class SignatureSpi
+ extends java.security.Signature
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+ private SecureRandom appRandom;
+
+ public SignatureSpi()
+ {
+ super("ECGOST3410");
+ this.digest = new GOST3411Digest();
+ this.signer = new ECGOST3410Signer();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else if (publicKey instanceof GOST3410Key)
+ {
+ param = GOST3410Util.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+ }
+
+ digest.reset();
+
+ if (appRandom != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, appRandom));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] sigBytes = new byte[64];
+ BigInteger[] sig = signer.generateSignature(hash);
+ byte[] r = sig[0].toByteArray();
+ byte[] s = sig[1].toByteArray();
+
+ if (s[0] != 0)
+ {
+ System.arraycopy(s, 0, sigBytes, 32 - s.length, s.length);
+ }
+ else
+ {
+ System.arraycopy(s, 1, sigBytes, 32 - (s.length - 1), s.length - 1);
+ }
+
+ if (r[0] != 0)
+ {
+ System.arraycopy(r, 0, sigBytes, 64 - r.length, r.length);
+ }
+ else
+ {
+ System.arraycopy(r, 1, sigBytes, 64 - (r.length - 1), r.length - 1);
+ }
+
+ return sigBytes;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ byte[] r = new byte[32];
+ byte[] s = new byte[32];
+
+ System.arraycopy(sigBytes, 0, s, 0, 32);
+
+ System.arraycopy(sigBytes, 32, r, 0, 32);
+
+ sig = new BigInteger[2];
+ sig[0] = new BigInteger(1, r);
+ sig[1] = new BigInteger(1, s);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java
new file mode 100644
index 000000000..65303d3d6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java
@@ -0,0 +1,230 @@
+package org.spongycastle.jcajce.provider.asymmetric.gost;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.GOST3410Signer;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.GOST3410Key;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.util.GOST3410Util;
+
+public class SignatureSpi
+ extends java.security.Signature
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+ private SecureRandom random;
+
+ public SignatureSpi()
+ {
+ super("GOST3410");
+ this.digest = new GOST3411Digest();
+ this.signer = new GOST3410Signer();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else if (publicKey instanceof GOST3410Key)
+ {
+ param = GOST3410Util.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+ }
+
+ digest.reset();
+
+ if (random != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, random));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] sigBytes = new byte[64];
+ BigInteger[] sig = signer.generateSignature(hash);
+ byte[] r = sig[0].toByteArray();
+ byte[] s = sig[1].toByteArray();
+
+ if (s[0] != 0)
+ {
+ System.arraycopy(s, 0, sigBytes, 32 - s.length, s.length);
+ }
+ else
+ {
+ System.arraycopy(s, 1, sigBytes, 32 - (s.length - 1), s.length - 1);
+ }
+
+ if (r[0] != 0)
+ {
+ System.arraycopy(r, 0, sigBytes, 64 - r.length, r.length);
+ }
+ else
+ {
+ System.arraycopy(r, 1, sigBytes, 64 - (r.length - 1), r.length - 1);
+ }
+
+ return sigBytes;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ byte[] r = new byte[32];
+ byte[] s = new byte[32];
+
+ System.arraycopy(sigBytes, 0, s, 0, 32);
+
+ System.arraycopy(sigBytes, 32, r, 0, 32);
+
+ sig = new BigInteger[2];
+ sig[0] = new BigInteger(1, r);
+ sig[1] = new BigInteger(1, s);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
new file mode 100644
index 000000000..2807ed4d0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -0,0 +1,368 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.Signature;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.MD2Digest;
+import org.spongycastle.crypto.digests.MD4Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.NullDigest;
+import org.spongycastle.crypto.digests.RIPEMD128Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.RIPEMD256Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+
+public class DigestSignatureSpi
+ extends Signature
+{
+ private Digest digest;
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmIdentifier algId;
+
+ // care - this constructor is actually used by outside organisations
+ protected DigestSignatureSpi(
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ super(digest.getAlgorithmName() + "withRSA");
+ this.digest = digest;
+ this.cipher = cipher;
+ this.algId = null;
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected DigestSignatureSpi(
+ ASN1ObjectIdentifier objId,
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ super(digest.getAlgorithmName() + "withRSA");
+ this.digest = digest;
+ this.cipher = cipher;
+ this.algId = new AlgorithmIdentifier(objId, DERNull.INSTANCE);
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key (" + getType(publicKey) + ") is not a RSAPublicKey instance");
+ }
+
+ CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance");
+ }
+
+ CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ digest.reset();
+
+ cipher.init(true, param);
+ }
+
+ private String getType(
+ Object o)
+ {
+ if (o == null)
+ {
+ return null;
+ }
+
+ return o.getClass().getName();
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] bytes = derEncode(hash);
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new SignatureException("key too small for signature type");
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = cipher.processBlock(sigBytes, 0, sigBytes.length);
+
+ expected = derEncode(hash);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if (sig.length == expected.length)
+ {
+ for (int i = 0; i < sig.length; i++)
+ {
+ if (sig[i] != expected[i])
+ {
+ return false;
+ }
+ }
+ }
+ else if (sig.length == expected.length - 2) // NULL left out
+ {
+ int sigOffset = sig.length - hash.length - 2;
+ int expectedOffset = expected.length - hash.length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ for (int i = 0; i < hash.length; i++)
+ {
+ if (sig[sigOffset + i] != expected[expectedOffset + i]) // check hash
+ {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ if (sig[i] != expected[i]) // check header less NULL
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ return null;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return null;
+ }
+
+ private byte[] derEncode(
+ byte[] hash)
+ throws IOException
+ {
+ if (algId == null)
+ {
+ // For raw RSA, the DigestInfo must be prepared externally
+ return hash;
+ }
+
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.getEncoded(ASN1Encoding.DER);
+ }
+
+ static public class SHA1
+ extends DigestSignatureSpi
+ {
+ public SHA1()
+ {
+ super(OIWObjectIdentifiers.idSHA1, new SHA1Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA224
+ extends DigestSignatureSpi
+ {
+ public SHA224()
+ {
+ super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA256
+ extends DigestSignatureSpi
+ {
+ public SHA256()
+ {
+ super(NISTObjectIdentifiers.id_sha256, new SHA256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA384
+ extends DigestSignatureSpi
+ {
+ public SHA384()
+ {
+ super(NISTObjectIdentifiers.id_sha384, new SHA384Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA512
+ extends DigestSignatureSpi
+ {
+ public SHA512()
+ {
+ super(NISTObjectIdentifiers.id_sha512, new SHA512Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD2
+ extends DigestSignatureSpi
+ {
+ public MD2()
+ {
+ super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD4
+ extends DigestSignatureSpi
+ {
+ public MD4()
+ {
+ super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD5
+ extends DigestSignatureSpi
+ {
+ public MD5()
+ {
+ super(PKCSObjectIdentifiers.md5, new MD5Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD160
+ extends DigestSignatureSpi
+ {
+ public RIPEMD160()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD128
+ extends DigestSignatureSpi
+ {
+ public RIPEMD128()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD256
+ extends DigestSignatureSpi
+ {
+ public RIPEMD256()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class noneRSA
+ extends DigestSignatureSpi
+ {
+ public noneRSA()
+ {
+ super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
new file mode 100644
index 000000000..e87ccff1e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
@@ -0,0 +1,143 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.Signature;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.signers.ISO9796d2Signer;
+
+public class ISOSignatureSpi
+ extends Signature
+{
+ private ISO9796d2Signer signer;
+
+ protected ISOSignatureSpi(
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ super(digest.getAlgorithmName() + "withRSA/ISO9796-2");
+ signer = new ISO9796d2Signer(cipher, digest, true);
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ signer.init(true, param);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ signer.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ signer.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ byte[] sig = signer.generateSignature();
+
+ return sig;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ boolean yes = signer.verifySignature(sigBytes);
+
+ return yes;
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ static public class SHA1WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public SHA1WithRSAEncryption()
+ {
+ super(new SHA1Digest(), new RSABlindedEngine());
+ }
+ }
+
+ static public class MD5WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public MD5WithRSAEncryption()
+ {
+ super(new MD5Digest(), new RSABlindedEngine());
+ }
+ }
+
+ static public class RIPEMD160WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public RIPEMD160WithRSAEncryption()
+ {
+ super(new RIPEMD160Digest(), new RSABlindedEngine());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java
new file mode 100644
index 000000000..9cf4485f9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java
@@ -0,0 +1,129 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+
+public abstract class DSABase
+ extends Signature
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ protected Digest digest;
+ protected DSA signer;
+ protected DSAEncoder encoder;
+ private SecureRandom appRandom;
+
+ protected DSABase(
+ String name,
+ Digest digest,
+ DSA signer,
+ DSAEncoder encoder)
+ {
+ super(name);
+
+ this.digest = digest;
+ this.signer = signer;
+ this.encoder = encoder;
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ doEngineInitSign(privateKey, appRandom);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+
+ return encoder.encode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ sig = encoder.decode(sigBytes);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ protected abstract void doEngineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException;
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
new file mode 100644
index 000000000..75d4eb269
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
@@ -0,0 +1,397 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.jce.provider.X509CRLObject;
+import org.spongycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class for dealing with X509 certificates.
+ * <p>
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+public class CertificateFactory
+ extends CertificateFactorySpi
+{
+ private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
+ private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
+
+ private ASN1Set sData = null;
+ private int sDataObjectCount = 0;
+ private InputStream currentStream = null;
+
+ private ASN1Set sCrlData = null;
+ private int sCrlDataObjectCount = 0;
+ private InputStream currentCrlStream = null;
+
+ private java.security.cert.Certificate readDERCertificate(
+ ASN1InputStream dIn)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+
+ return getCertificate();
+ }
+ }
+
+ return new X509CertificateObject(
+ Certificate.getInstance(seq));
+ }
+
+ private java.security.cert.Certificate getCertificate()
+ throws CertificateParsingException
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.size())
+ {
+ Object obj = sData.getObjectAt(sDataObjectCount++);
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new X509CertificateObject(
+ Certificate.getInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private java.security.cert.Certificate readPEMCertificate(
+ InputStream in)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return new X509CertificateObject(
+ Certificate.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ protected CRL createCRL(CertificateList c)
+ throws CRLException
+ {
+ return new X509CRLObject(c);
+ }
+
+ private CRL readPEMCRL(
+ InputStream in)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ private CRL readDERCRL(
+ ASN1InputStream aIn)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = (ASN1Sequence)aIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sCrlData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
+
+ return getCRL();
+ }
+ }
+
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ private CRL getCRL()
+ throws CRLException
+ {
+ if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size())
+ {
+ return null;
+ }
+
+ return createCRL(
+ CertificateList.getInstance(
+ sCrlData.getObjectAt(sCrlDataObjectCount++)));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public java.security.cert.Certificate engineGenerateCertificate(
+ InputStream in)
+ throws CertificateException
+ {
+ if (currentStream == null)
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != in) // reset if input stream has changed
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.size())
+ {
+ return getCertificate();
+ }
+ else
+ {
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(in);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCertificate(pis);
+ }
+ else
+ {
+ return readDERCertificate(new ASN1InputStream(pis));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExCertificateException(e);
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public Collection engineGenerateCertificates(
+ InputStream inStream)
+ throws CertificateException
+ {
+ java.security.cert.Certificate cert;
+ List certs = new ArrayList();
+
+ while ((cert = engineGenerateCertificate(inStream)) != null)
+ {
+ certs.add(cert);
+ }
+
+ return certs;
+ }
+
+ /**
+ * Generates a certificate revocation list (CRL) object and initializes
+ * it with the data read from the input stream inStream.
+ */
+ public CRL engineGenerateCRL(
+ InputStream inStream)
+ throws CRLException
+ {
+ if (currentCrlStream == null)
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+ else if (currentCrlStream != inStream) // reset if input stream has changed
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sCrlData != null)
+ {
+ if (sCrlDataObjectCount != sCrlData.size())
+ {
+ return getCRL();
+ }
+ else
+ {
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(inStream);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCRL(pis);
+ }
+ else
+ { // lazy evaluate to help processing of large CRLs
+ return readDERCRL(new ASN1InputStream(pis, true));
+ }
+ }
+ catch (CRLException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the CRLs read from
+ * the given input stream inStream.
+ *
+ * The inStream may contain a sequence of DER-encoded CRLs, or
+ * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
+ * only signficant field being crls. In particular the signature
+ * and the contents are ignored.
+ */
+ public Collection engineGenerateCRLs(
+ InputStream inStream)
+ throws CRLException
+ {
+ CRL crl;
+ List crls = new ArrayList();
+
+ while ((crl = engineGenerateCRL(inStream)) != null)
+ {
+ crls.add(crl);
+ }
+
+ return crls;
+ }
+
+ public Iterator engineGetCertPathEncodings()
+ {
+ return null; // TODO: PKIXCertPath.certPathEncodings.iterator();
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream)
+ throws CertificateException
+ {
+ return engineGenerateCertPath(inStream, "PkiPath");
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ return new PKIXCertPath(inStream, encoding);
+ }
+
+ public CertPath engineGenerateCertPath(
+ List certificates)
+ throws CertificateException
+ {
+ Iterator iter = certificates.iterator();
+ Object obj;
+ while (iter.hasNext())
+ {
+ obj = iter.next();
+ if (obj != null)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ throw new CertificateException("list contains non X509Certificate object while creating CertPath\n" + obj.toString());
+ }
+ }
+ }
+ return new PKIXCertPath(certificates);
+ }
+
+ private class ExCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public ExCertificateException(Throwable cause)
+ {
+ this.cause = cause;
+ }
+
+ public ExCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
new file mode 100644
index 000000000..a2462a9a0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
@@ -0,0 +1,379 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.io.pem.PemObject;
+import org.spongycastle.util.io.pem.PemWriter;
+
+/**
+ * CertPath implementation for X.509 certificates.
+ * <br />
+ **/
+public class PKIXCertPath
+ extends CertPath
+{
+ static final List certPathEncodings;
+
+ static
+ {
+ List encodings = new ArrayList();
+ encodings.add("PkiPath");
+ encodings.add("PEM");
+ encodings.add("PKCS7");
+ certPathEncodings = Collections.unmodifiableList(encodings);
+ }
+
+ private List certificates;
+
+ /**
+ * @param certs
+ */
+ private List sortCerts(
+ List certs)
+ {
+ try
+ {
+ if (certs.size() < 2)
+ {
+ return certs;
+ }
+
+ X509Principal issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)certs.get(0)));
+ boolean okay = true;
+
+ for (int i = 1; i != certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+
+ if (issuer.equals(PrincipalUtil.getSubjectX509Principal(cert)))
+ {
+ issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)certs.get(i)));
+ }
+ else
+ {
+ okay = false;
+ break;
+ }
+ }
+
+ if (okay)
+ {
+ return certs;
+ }
+
+ // find end-entity cert
+ List retList = new ArrayList(certs.size());
+ List orig = new ArrayList(certs);
+
+ for (int i = 0; i < certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+ boolean found = false;
+
+ X509Principal subject = PrincipalUtil.getSubjectX509Principal(cert);
+
+ for (int j = 0; j != certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (PrincipalUtil.getIssuerX509Principal(c).equals(subject))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ retList.add(cert);
+ certs.remove(i);
+ }
+ }
+
+ // can only have one end entity cert - something's wrong, give up.
+ if (retList.size() > 1)
+ {
+ return orig;
+ }
+
+ for (int i = 0; i != retList.size(); i++)
+ {
+ issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)retList.get(i)));
+
+ for (int j = 0; j < certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (issuer.equals(PrincipalUtil.getSubjectX509Principal(c)))
+ {
+ retList.add(c);
+ certs.remove(j);
+ break;
+ }
+ }
+ }
+
+ // make sure all certificates are accounted for.
+ if (certs.size() > 0)
+ {
+ return orig;
+ }
+
+ return retList;
+ }
+ catch (Exception e)
+ {
+ return certs;
+ }
+ }
+
+ PKIXCertPath(List certificates)
+ {
+ super("X.509");
+ this.certificates = sortCerts(new ArrayList(certificates));
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ **/
+ PKIXCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ super("X.509");
+ try
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Primitive derObject = derInStream.readObject();
+ if (!(derObject instanceof ASN1Sequence))
+ {
+ throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+ }
+ Enumeration e = ((ASN1Sequence)derObject).getObjects();
+ certificates = new ArrayList();
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ while (e.hasMoreElements())
+ {
+ ASN1Encodable element = (ASN1Encodable)e.nextElement();
+ byte[] encoded = element.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ certificates.add(0, certFactory.generateCertificate(
+ new ByteArrayInputStream(encoded)));
+ }
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7") || encoding.equalsIgnoreCase("PEM"))
+ {
+ inStream = new BufferedInputStream(inStream);
+ certificates = new ArrayList();
+ CertificateFactory certFactory= CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ Certificate cert;
+ while ((cert = certFactory.generateCertificate(inStream)) != null)
+ {
+ certificates.add(cert);
+ }
+ }
+ else
+ {
+ throw new CertificateException("unsupported encoding: " + encoding);
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString());
+ }
+ catch (NoSuchProviderException ex)
+ {
+ throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString());
+ }
+
+ this.certificates = sortCerts(certificates);
+ }
+
+ /**
+ * Returns an iteration of the encodings supported by this
+ * certification path, with the default encoding
+ * first. Attempts to modify the returned Iterator via its
+ * remove method result in an UnsupportedOperationException.
+ *
+ * @return an Iterator over the names of the supported encodings (as Strings)
+ **/
+ public Iterator getEncodings()
+ {
+ return certPathEncodings.iterator();
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the default encoding.
+ *
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error occurs
+ **/
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ Iterator iter = getEncodings();
+ if (iter.hasNext())
+ {
+ Object enc = iter.next();
+ if (enc instanceof String)
+ {
+ return getEncoded((String)enc);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the specified encoding.
+ *
+ * @param encoding the name of the encoding to use
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error
+ * occurs or the encoding requested is not supported
+ *
+ **/
+ public byte[] getEncoded(String encoding)
+ throws CertificateEncodingException
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ ListIterator iter = certificates.listIterator(certificates.size());
+ while (iter.hasPrevious())
+ {
+ v.add(toASN1Object((X509Certificate)iter.previous()));
+ }
+
+ return toDEREncoded(new DERSequence(v));
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7"))
+ {
+ ContentInfo encInfo = new ContentInfo(PKCSObjectIdentifiers.data, null);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ v.add(toASN1Object((X509Certificate)certificates.get(i)));
+ }
+
+ SignedData sd = new SignedData(
+ new ASN1Integer(1),
+ new DERSet(),
+ encInfo,
+ new DERSet(v),
+ null,
+ new DERSet());
+
+ return toDEREncoded(new ContentInfo(
+ PKCSObjectIdentifiers.signedData, sd));
+ }
+ else if (encoding.equalsIgnoreCase("PEM"))
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
+
+ try
+ {
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
+ }
+
+ pWrt.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+ }
+
+ return bOut.toByteArray();
+ }
+ else
+ {
+ throw new CertificateEncodingException("unsupported encoding: " + encoding);
+ }
+ }
+
+ /**
+ * Returns the list of certificates in this certification
+ * path. The List returned must be immutable and thread-safe.
+ *
+ * @return an immutable List of Certificates (may be empty, but not null)
+ **/
+ public List getCertificates()
+ {
+ return Collections.unmodifiableList(new ArrayList(certificates));
+ }
+
+ /**
+ * Return a DERObject containing the encoded certificate.
+ *
+ * @param cert the X509Certificate object to be encoded
+ *
+ * @return the DERObject
+ **/
+ private ASN1Primitive toASN1Object(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return new ASN1InputStream(cert.getEncoded()).readObject();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Exception while encoding certificate: " + e.toString());
+ }
+ }
+
+ private byte[] toDEREncoded(ASN1Encodable obj)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException("Exception thrown: " + e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
new file mode 100644
index 000000000..e3dc0876b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
@@ -0,0 +1,107 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+class SignatureUtil
+{
+ private static final ASN1Null derNull = new DERNull();
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1";
+ }
+ if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+ {
+ ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+
+ return getDigestAlgName((ASN1ObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.getAlgorithm().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ ASN1ObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/MultiCertStoreParameters.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/MultiCertStoreParameters.java
new file mode 100644
index 000000000..8762494b2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/MultiCertStoreParameters.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jce;
+
+import java.security.cert.CertStoreParameters;
+import java.util.Collection;
+
+public class MultiCertStoreParameters
+ implements CertStoreParameters
+{
+ private Collection certStores;
+ private boolean searchAllStores;
+
+ /**
+ * Create a parameters object which specifies searching of all the passed in stores.
+ *
+ * @param certStores CertStores making up the multi CertStore
+ */
+ public MultiCertStoreParameters(Collection certStores)
+ {
+ this(certStores, true);
+ }
+
+ /**
+ * Create a parameters object which can be to used to make a multi store made up
+ * of the passed in CertStores. If the searchAllStores parameter is false, any search on
+ * the multi-store will terminate as soon as a search query produces a result.
+ *
+ * @param certStores CertStores making up the multi CertStore
+ * @param searchAllStores true if all CertStores should be searched on request, false if a result
+ * should be returned on the first successful CertStore query.
+ */
+ public MultiCertStoreParameters(Collection certStores, boolean searchAllStores)
+ {
+ this.certStores = certStores;
+ this.searchAllStores = searchAllStores;
+ }
+
+ public Collection getCertStores()
+ {
+ return certStores;
+ }
+
+ public boolean getSearchAllStores()
+ {
+ return searchAllStores;
+ }
+
+ public Object clone()
+ {
+ return this;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/netscape/NetscapeCertRequest.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/netscape/NetscapeCertRequest.java
new file mode 100644
index 000000000..45d7975a6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/netscape/NetscapeCertRequest.java
@@ -0,0 +1,296 @@
+package org.spongycastle.jce.netscape;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ *
+ *
+ * Handles NetScape certificate request (KEYGEN), these are constructed as:
+ * <pre><code>
+ * SignedPublicKeyAndChallenge ::= SEQUENCE {
+ * publicKeyAndChallenge PublicKeyAndChallenge,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ *
+ * PublicKey's encoded-format has to be X.509.
+ *
+ **/
+public class NetscapeCertRequest
+ extends ASN1Object
+{
+ AlgorithmIdentifier sigAlg;
+ AlgorithmIdentifier keyAlg;
+ byte sigBits [];
+ String challenge;
+ DERBitString content;
+ PublicKey pubkey ;
+
+ private static ASN1Sequence getReq(
+ byte[] r)
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(r));
+
+ return ASN1Sequence.getInstance(aIn.readObject());
+ }
+
+ public NetscapeCertRequest(
+ byte[] req)
+ throws IOException
+ {
+ this(getReq(req));
+ }
+
+ public NetscapeCertRequest (ASN1Sequence spkac)
+ {
+ try
+ {
+
+ //
+ // SignedPublicKeyAndChallenge ::= SEQUENCE {
+ // publicKeyAndChallenge PublicKeyAndChallenge,
+ // signatureAlgorithm AlgorithmIdentifier,
+ // signature BIT STRING
+ // }
+ //
+ if (spkac.size() != 3)
+ {
+ throw new IllegalArgumentException("invalid SPKAC (size):"
+ + spkac.size());
+ }
+
+ sigAlg = new AlgorithmIdentifier((ASN1Sequence)spkac
+ .getObjectAt(1));
+ sigBits = ((DERBitString)spkac.getObjectAt(2)).getBytes();
+
+ //
+ // PublicKeyAndChallenge ::= SEQUENCE {
+ // spki SubjectPublicKeyInfo,
+ // challenge IA5STRING
+ // }
+ //
+ ASN1Sequence pkac = (ASN1Sequence)spkac.getObjectAt(0);
+
+ if (pkac.size() != 2)
+ {
+ throw new IllegalArgumentException("invalid PKAC (len): "
+ + pkac.size());
+ }
+
+ challenge = ((DERIA5String)pkac.getObjectAt(1)).getString();
+
+ //this could be dangerous, as ASN.1 decoding/encoding
+ //could potentially alter the bytes
+ content = new DERBitString(pkac);
+
+ SubjectPublicKeyInfo pubkeyinfo = new SubjectPublicKeyInfo(
+ (ASN1Sequence)pkac.getObjectAt(0));
+
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(
+ pubkeyinfo).getBytes());
+
+ keyAlg = pubkeyinfo.getAlgorithmId();
+ pubkey = KeyFactory.getInstance(keyAlg.getObjectId().getId(), "SC")
+ .generatePublic(xspec);
+
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException(e.toString());
+ }
+ }
+
+ public NetscapeCertRequest(
+ String challenge,
+ AlgorithmIdentifier signing_alg,
+ PublicKey pub_key) throws NoSuchAlgorithmException,
+ InvalidKeySpecException, NoSuchProviderException, IOException
+ {
+
+ this.challenge = challenge;
+ sigAlg = signing_alg;
+ pubkey = pub_key;
+
+ ASN1EncodableVector content_der = new ASN1EncodableVector();
+ content_der.add(getKeySpec());
+ //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
+ content_der.add(new DERIA5String(challenge));
+
+ content = new DERBitString(new DERSequence(content_der));
+ }
+
+ public String getChallenge()
+ {
+ return challenge;
+ }
+
+ public void setChallenge(String value)
+ {
+ challenge = value;
+ }
+
+ public AlgorithmIdentifier getSigningAlgorithm()
+ {
+ return sigAlg;
+ }
+
+ public void setSigningAlgorithm(AlgorithmIdentifier value)
+ {
+ sigAlg = value;
+ }
+
+ public AlgorithmIdentifier getKeyAlgorithm()
+ {
+ return keyAlg;
+ }
+
+ public void setKeyAlgorithm(AlgorithmIdentifier value)
+ {
+ keyAlg = value;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ return pubkey;
+ }
+
+ public void setPublicKey(PublicKey value)
+ {
+ pubkey = value;
+ }
+
+ public boolean verify(String challenge) throws NoSuchAlgorithmException,
+ InvalidKeyException, SignatureException, NoSuchProviderException
+ {
+ if (!challenge.equals(this.challenge))
+ {
+ return false;
+ }
+
+ //
+ // Verify the signature .. shows the response was generated
+ // by someone who knew the associated private key
+ //
+ Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
+ "SC");
+ sig.initVerify(pubkey);
+ sig.update(content.getBytes());
+
+ return sig.verify(sigBits);
+ }
+
+ public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException,
+ InvalidKeyException, SignatureException, NoSuchProviderException,
+ InvalidKeySpecException
+ {
+ sign(priv_key, null);
+ }
+
+ public void sign(PrivateKey priv_key, SecureRandom rand)
+ throws NoSuchAlgorithmException, InvalidKeyException,
+ SignatureException, NoSuchProviderException,
+ InvalidKeySpecException
+ {
+ Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(),
+ "SC");
+
+ if (rand != null)
+ {
+ sig.initSign(priv_key);
+ }
+ else
+ {
+ sig.initSign(priv_key);
+ }
+
+ ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+ pkac.add(getKeySpec());
+ pkac.add(new DERIA5String(challenge));
+
+ try
+ {
+ sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException ioe)
+ {
+ throw new SignatureException(ioe.getMessage());
+ }
+
+ sigBits = sig.sign();
+ }
+
+ private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException,
+ InvalidKeySpecException, NoSuchProviderException
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ ASN1Primitive obj = null;
+ try
+ {
+
+ baos.write(pubkey.getEncoded());
+ baos.close();
+
+ ASN1InputStream derin = new ASN1InputStream(
+ new ByteArrayInputStream(baos.toByteArray()));
+
+ obj = derin.readObject();
+ }
+ catch (IOException ioe)
+ {
+ throw new InvalidKeySpecException(ioe.getMessage());
+ }
+ return obj;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector spkac = new ASN1EncodableVector();
+ ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+ try
+ {
+ pkac.add(getKeySpec());
+ }
+ catch (Exception e)
+ {
+ //ignore
+ }
+
+ pkac.add(new DERIA5String(challenge));
+
+ spkac.add(new DERSequence(pkac));
+ spkac.add(sigAlg);
+ spkac.add(new DERBitString(sigBits));
+
+ return new DERSequence(spkac);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/AnnotatedException.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/AnnotatedException.java
new file mode 100644
index 000000000..8c115d984
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/AnnotatedException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.jce.provider;
+
+public class AnnotatedException
+ extends Exception
+{
+ private Throwable _underlyingException;
+
+ AnnotatedException(String string, Throwable e)
+ {
+ super(string);
+
+ _underlyingException = e;
+ }
+
+ AnnotatedException(String string)
+ {
+ this(string, null);
+ }
+
+ Throwable getUnderlyingException()
+ {
+ return _underlyingException;
+ }
+
+ public Throwable getCause()
+ {
+ return _underlyingException;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/BouncyCastleProvider.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/BouncyCastleProvider.java
new file mode 100644
index 000000000..87a086068
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/BouncyCastleProvider.java
@@ -0,0 +1,274 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * To add the provider at runtime use:
+ * <pre>
+ * import java.security.Security;
+ * import org.spongycastle.jce.provider.BouncyCastleProvider;
+ *
+ * Security.addProvider(new BouncyCastleProvider());
+ * </pre>
+ * The provider can also be configured as part of your environment via
+ * static registration by adding an entry to the java.security properties
+ * file (found in $JAVA_HOME/jre/lib/security/java.security, where
+ * $JAVA_HOME is the location of your JDK/JRE distribution). You'll find
+ * detailed instructions in the file but basically it comes down to adding
+ * a line:
+ * <pre>
+ * <code>
+ * security.provider.&lt;n&gt;=org.spongycastle.jce.provider.BouncyCastleProvider
+ * </code>
+ * </pre>
+ * Where &lt;n&gt; is the preference you want the provider at (1 being the
+ * most preferred).
+ * <p>Note: JCE algorithm names should be upper-case only so the case insensitive
+ * test for getInstance works.
+ */
+public final class BouncyCastleProvider extends Provider
+ implements ConfigurableProvider
+{
+ private static String info = "BouncyCastle Security Provider v1.50";
+
+ public static final String PROVIDER_NAME = "SC";
+
+ public static final ProviderConfiguration CONFIGURATION = new BouncyCastleProviderConfiguration();
+
+ private static final Map keyInfoConverters = new HashMap();
+
+ /*
+ * Configurable symmetric ciphers
+ */
+ private static final String SYMMETRIC_PACKAGE = "org.spongycastle.jcajce.provider.symmetric.";
+
+ private static final String[] SYMMETRIC_GENERIC =
+ {
+ "PBEPBKDF2", "PBEPKCS12"
+ };
+
+ private static final String[] SYMMETRIC_MACS =
+ {
+ "SipHash"
+ };
+
+ private static final String[] SYMMETRIC_CIPHERS =
+ {
+ "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede",
+ "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5",
+ "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "TEA", "Twofish", "Threefish",
+ "VMPC", "VMPCKSA3", "XTEA", "XSalsa20"
+ };
+
+ /*
+ * Configurable asymmetric ciphers
+ */
+ private static final String ASYMMETRIC_PACKAGE = "org.spongycastle.jcajce.provider.asymmetric.";
+
+ // this one is required for GNU class path - it needs to be loaded first as the
+ // later ones configure it.
+ private static final String[] ASYMMETRIC_GENERIC =
+ {
+ "X509", "IES"
+ };
+
+ private static final String[] ASYMMETRIC_CIPHERS =
+ {
+ "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145"
+ };
+
+ /*
+ * Configurable digests
+ */
+ private static final String DIGEST_PACKAGE = "org.spongycastle.jcajce.provider.digest.";
+ private static final String[] DIGESTS =
+ {
+ "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool"
+ };
+
+ /*
+ * Configurable keystores
+ */
+ private static final String KEYSTORE_PACKAGE = "org.spongycastle.jcajce.provider.keystore.";
+ private static final String[] KEYSTORES =
+ {
+ "SC", "PKCS12"
+ };
+
+ /**
+ * Construct a new provider. This should only be required when
+ * using runtime registration of the provider using the
+ * <code>Security.addProvider()</code> mechanism.
+ */
+ public BouncyCastleProvider()
+ {
+ super(PROVIDER_NAME, 1.50, info);
+
+ setup();
+ }
+
+ private void setup()
+ {
+ loadAlgorithms(DIGEST_PACKAGE, DIGESTS);
+
+ loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_GENERIC);
+
+ loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_MACS);
+
+ loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_CIPHERS);
+
+ loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_GENERIC);
+
+ loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_CIPHERS);
+
+ loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES);
+
+ //
+ // X509Store
+ //
+ put("X509Store.CERTIFICATE/COLLECTION", "org.spongycastle.jce.provider.X509StoreCertCollection");
+ put("X509Store.ATTRIBUTECERTIFICATE/COLLECTION", "org.spongycastle.jce.provider.X509StoreAttrCertCollection");
+ put("X509Store.CRL/COLLECTION", "org.spongycastle.jce.provider.X509StoreCRLCollection");
+ put("X509Store.CERTIFICATEPAIR/COLLECTION", "org.spongycastle.jce.provider.X509StoreCertPairCollection");
+
+ put("X509Store.CERTIFICATE/LDAP", "org.spongycastle.jce.provider.X509StoreLDAPCerts");
+ put("X509Store.CRL/LDAP", "org.spongycastle.jce.provider.X509StoreLDAPCRLs");
+ put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "org.spongycastle.jce.provider.X509StoreLDAPAttrCerts");
+ put("X509Store.CERTIFICATEPAIR/LDAP", "org.spongycastle.jce.provider.X509StoreLDAPCertPairs");
+
+ //
+ // X509StreamParser
+ //
+ put("X509StreamParser.CERTIFICATE", "org.spongycastle.jce.provider.X509CertParser");
+ put("X509StreamParser.ATTRIBUTECERTIFICATE", "org.spongycastle.jce.provider.X509AttrCertParser");
+ put("X509StreamParser.CRL", "org.spongycastle.jce.provider.X509CRLParser");
+ put("X509StreamParser.CERTIFICATEPAIR", "org.spongycastle.jce.provider.X509CertPairParser");
+
+ //
+ // cipher engines
+ //
+ put("Cipher.BROKENPBEWITHMD5ANDDES", "org.spongycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES");
+
+ put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.spongycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
+
+
+ put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.spongycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
+
+ // Certification Path API
+ put("CertPathValidator.RFC3281", "org.spongycastle.jce.provider.PKIXAttrCertPathValidatorSpi");
+ put("CertPathBuilder.RFC3281", "org.spongycastle.jce.provider.PKIXAttrCertPathBuilderSpi");
+ put("CertPathValidator.RFC3280", "org.spongycastle.jce.provider.PKIXCertPathValidatorSpi");
+ put("CertPathBuilder.RFC3280", "org.spongycastle.jce.provider.PKIXCertPathBuilderSpi");
+ put("CertPathValidator.PKIX", "org.spongycastle.jce.provider.PKIXCertPathValidatorSpi");
+ put("CertPathBuilder.PKIX", "org.spongycastle.jce.provider.PKIXCertPathBuilderSpi");
+ put("CertStore.Collection", "org.spongycastle.jce.provider.CertStoreCollectionSpi");
+ put("CertStore.LDAP", "org.spongycastle.jce.provider.X509LDAPCertStoreSpi");
+ put("CertStore.Multi", "org.spongycastle.jce.provider.MultiCertStoreSpi");
+ put("Alg.Alias.CertStore.X509LDAP", "LDAP");
+ }
+
+ private void loadAlgorithms(String packageName, String[] names)
+ {
+ for (int i = 0; i != names.length; i++)
+ {
+ Class clazz = null;
+ try
+ {
+ ClassLoader loader = this.getClass().getClassLoader();
+
+ if (loader != null)
+ {
+ clazz = loader.loadClass(packageName + names[i] + "$Mappings");
+ }
+ else
+ {
+ clazz = Class.forName(packageName + names[i] + "$Mappings");
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ // ignore
+ }
+
+ if (clazz != null)
+ {
+ try
+ {
+ ((AlgorithmProvider)clazz.newInstance()).configure(this);
+ }
+ catch (Exception e)
+ { // this should never ever happen!!
+ throw new InternalError("cannot create instance of "
+ + packageName + names[i] + "$Mappings : " + e);
+ }
+ }
+ }
+ }
+
+ public void setParameter(String parameterName, Object parameter)
+ {
+ synchronized (CONFIGURATION)
+ {
+ ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
+ }
+ }
+
+ public boolean hasAlgorithm(String type, String name)
+ {
+ return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
+ }
+
+ public void addAlgorithm(String key, String value)
+ {
+ if (containsKey(key))
+ {
+ throw new IllegalStateException("duplicate provider key (" + key + ") found");
+ }
+
+ put(key, value);
+ }
+
+ public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
+ {
+ keyInfoConverters.put(oid, keyInfoConverter);
+ }
+
+ public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePublic(publicKeyInfo);
+ }
+
+ public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePrivate(privateKeyInfo);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java
new file mode 100644
index 000000000..bfeedb2ad
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java
@@ -0,0 +1,108 @@
+package org.spongycastle.jce.provider;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+class BouncyCastleProviderConfiguration
+ implements ProviderConfiguration
+{
+ private volatile ECParameterSpec ecImplicitCaParams;
+ private volatile Object dhDefaultParams;
+
+ void setParameter(String parameterName, Object parameter)
+ {
+ SecurityManager securityManager = System.getSecurityManager();
+
+ if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+ {
+ ECParameterSpec curveSpec;
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ curveSpec = (ECParameterSpec)parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid ECParameterSpec");
+ }
+
+ ecImplicitCaParams = (ECParameterSpec)curveSpec;
+ }
+ else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+ {
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ ecImplicitCaParams = (ECParameterSpec)parameter;
+ }
+ else // assume java.security.spec
+ {
+ throw new IllegalArgumentException("not a valid ECParameterSpec");
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS))
+ {
+ Object dhSpec;
+
+
+ if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+ {
+ dhSpec = parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec");
+ }
+
+ dhDefaultParams = dhSpec;
+ }
+ else if (parameterName.equals(ConfigurableProvider.DH_DEFAULT_PARAMS))
+ {
+
+ if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+ {
+ dhDefaultParams = parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]");
+ }
+ }
+ }
+
+ public ECParameterSpec getEcImplicitlyCa()
+ {
+ return ecImplicitCaParams;
+ }
+
+ public DHParameterSpec getDHDefaultParameters(int keySize)
+ {
+ Object params = dhDefaultParams;
+
+ if (params instanceof DHParameterSpec)
+ {
+ DHParameterSpec spec = (DHParameterSpec)params;
+
+ if (spec.getP().bitLength() == keySize)
+ {
+ return spec;
+ }
+ }
+ else if (params instanceof DHParameterSpec[])
+ {
+ DHParameterSpec[] specs = (DHParameterSpec[])params;
+
+ for (int i = 0; i != specs.length; i++)
+ {
+ if (specs[i].getP().bitLength() == keySize)
+ {
+ return specs[i];
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/CertStoreCollectionSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/CertStoreCollectionSpi.java
new file mode 100644
index 000000000..19a361ae4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/CertStoreCollectionSpi.java
@@ -0,0 +1,104 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import java.security.cert.CollectionCertStoreParameters;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class CertStoreCollectionSpi extends CertStoreSpi
+{
+ private CollectionCertStoreParameters params;
+
+ public CertStoreCollectionSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof CollectionCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException( "org.spongycastle.jce.provider.CertStoreCollectionSpi: parameter must be a CollectionCertStoreParameters object\n" + params.toString() );
+ }
+
+ this.params = (CollectionCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(
+ CertSelector selector)
+ throws CertStoreException
+ {
+ Set col = new HashSet();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof Certificate)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof Certificate) && selector.match((Certificate)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+
+
+ public Collection engineGetCRLs(
+ CRLSelector selector)
+ throws CertStoreException
+ {
+ Set col = new HashSet();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof CRL)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof CRL) && selector.match((CRL)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/MultiCertStoreSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/MultiCertStoreSpi.java
new file mode 100644
index 000000000..c6db1bdbd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/MultiCertStoreSpi.java
@@ -0,0 +1,85 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.jce.MultiCertStoreParameters;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public class MultiCertStoreSpi
+ extends CertStoreSpi
+{
+ private MultiCertStoreParameters params;
+
+ public MultiCertStoreSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof MultiCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.MultiCertStoreSpi: parameter must be a MultiCertStoreParameters object\n" + params.toString());
+ }
+
+ this.params = (MultiCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(CertSelector certSelector)
+ throws CertStoreException
+ {
+ boolean searchAllStores = params.getSearchAllStores();
+ Iterator iter = params.getCertStores().iterator();
+ List allCerts = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST;
+
+ while (iter.hasNext())
+ {
+ CertStore store = (CertStore)iter.next();
+ Collection certs = store.getCertificates(certSelector);
+
+ if (searchAllStores)
+ {
+ allCerts.addAll(certs);
+ }
+ else if (!certs.isEmpty())
+ {
+ return certs;
+ }
+ }
+
+ return allCerts;
+ }
+
+ public Collection engineGetCRLs(CRLSelector crlSelector)
+ throws CertStoreException
+ {
+ boolean searchAllStores = params.getSearchAllStores();
+ Iterator iter = params.getCertStores().iterator();
+ List allCRLs = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST;
+
+ while (iter.hasNext())
+ {
+ CertStore store = (CertStore)iter.next();
+ Collection crls = store.getCRLs(crlSelector);
+
+ if (searchAllStores)
+ {
+ allCRLs.addAll(crls);
+ }
+ else if (!crls.isEmpty())
+ {
+ return crls;
+ }
+ }
+
+ return allCRLs;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java
new file mode 100644
index 000000000..e09a3526f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java
@@ -0,0 +1,365 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import java.security.cert.*;
+import org.spongycastle.jce.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Implements the PKIX CertPathBuilding algorithem for BouncyCastle.
+ * <br />
+ * <b>MAYBE: implement more CertPath validation whil build path to omit invalid pathes</b>
+ *
+ * @see CertPathBuilderSpi
+ **/
+public class PKIXCertPathBuilderSpi
+ extends CertPathBuilderSpi
+{
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all
+ * information to build the CertPath
+ **/
+ public CertPathBuilderResult engineBuild(
+ CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXBuilderParameters))
+ {
+ throw new InvalidAlgorithmParameterException("params must be a PKIXBuilderParameters instance");
+ }
+
+ PKIXBuilderParameters pkixParams = (PKIXBuilderParameters)params;
+
+ Collection targets;
+ Iterator targetIter;
+ List certPathList = new ArrayList();
+ X509Certificate cert;
+ Collection certs;
+ CertPath certPath = null;
+ Exception certPathException = null;
+
+ // search target certificates
+ CertSelector certSelect = pkixParams.getTargetCertConstraints();
+ if (certSelect == null)
+ {
+ throw new CertPathBuilderException("targetCertConstraints must be non-null for CertPath building");
+ }
+
+ try
+ {
+ targets = findCertificates(certSelect, pkixParams.getCertStores());
+ }
+ catch (CertStoreException e)
+ {
+ throw new CertPathBuilderException(e);
+ }
+
+ if (targets.isEmpty())
+ {
+ throw new CertPathBuilderException("no certificate found matching targetCertContraints");
+ }
+
+ CertificateFactory cFact;
+ CertPathValidator validator;
+
+ try
+ {
+ cFact = CertificateFactory.getInstance("X.509", "SC");
+ validator = CertPathValidator.getInstance("PKIX", "SC");
+ }
+ catch (Exception e)
+ {
+ throw new CertPathBuilderException("exception creating support classes: " + e);
+ }
+
+ //
+ // check all potential target certificates
+ targetIter = targets.iterator();
+ while (targetIter.hasNext())
+ {
+ cert = (X509Certificate)targetIter.next();
+ certPathList.clear();
+ while (cert != null)
+ {
+ // add cert to the certpath
+ certPathList.add(cert);
+
+ // check wether the issuer of <cert> is a TrustAnchor
+ if (findTrustAnchor(cert, pkixParams.getTrustAnchors()) != null)
+ {
+ try
+ {
+ certPath = cFact.generateCertPath(certPathList);
+
+ PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)validator.validate(certPath, pkixParams);
+
+ return new PKIXCertPathBuilderResult(certPath,
+ result.getTrustAnchor(),
+ result.getPolicyTree(),
+ result.getPublicKey());
+ }
+ catch (CertificateException ex)
+ {
+ certPathException = ex;
+ }
+ catch (CertPathValidatorException ex)
+ {
+ certPathException = ex;
+ }
+ // if validation failed go to next certificate
+ cert = null;
+ }
+ else
+ {
+ // try to get the issuer certificate from one
+ // of the CertStores
+ try
+ {
+ X509Certificate issuer = findIssuer(cert, pkixParams.getCertStores());
+ if (issuer.equals(cert))
+ {
+ cert = null;
+ }
+ else
+ {
+ cert = issuer;
+ }
+ }
+ catch (CertPathValidatorException ex)
+ {
+ certPathException = ex;
+ cert = null;
+ }
+ }
+ }
+ }
+
+ if (certPath != null)
+ {
+ throw new CertPathBuilderException("found certificate chain, but could not be validated", certPathException);
+ }
+
+ throw new CertPathBuilderException("unable to find certificate chain");
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the fiven X509 certificate.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ *
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ *
+ * @exception CertPathValidatorException if a TrustAnchor was
+ * found but the signature verificytion on the given certificate
+ * has thrown an exception. This Exception can be obtainted with
+ * <code>getCause()</code> method.
+ **/
+ final TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors)
+ throws CertPathBuilderException
+ {
+ Iterator iter = trustAnchors.iterator();
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+
+ try
+ {
+ certSelectX509.setSubject(PrincipalUtil.getIssuerX509Principal(cert).getEncoded());
+ }
+ catch (CertificateEncodingException ex)
+ {
+ throw new CertPathBuilderException("can't get trust anchor principal",null);
+ }
+ catch (IOException ex)
+ {
+ throw new CertPathBuilderException("can't get trust anchor principal",null);
+ }
+
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X509Principal certIssuer = PrincipalUtil.getIssuerX509Principal(cert);
+ X509Principal caName = new X509Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (CertificateEncodingException ex)
+ {
+ trust = null;
+ }
+ catch (IllegalArgumentException ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ cert.verify(trustPublicKey);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new CertPathBuilderException("TrustAnchor found put certificate validation failed",invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ /**
+ * Return a Collection of all certificates found in the
+ * CertStore's that are matching the certSelect criteriums.
+ *
+ * @param certSelector a {@link CertSelector CertSelector}
+ * object that will be used to select the certificates
+ * @param certStores a List containing only {@link CertStore
+ * CertStore} objects. These are used to search for
+ * certificates
+ *
+ * @return a Collection of all found {@link Certificate Certificate}
+ * objects. May be empty but never <code>null</code>.
+ **/
+ private Collection findCertificates(
+ CertSelector certSelect,
+ List certStores)
+ throws CertStoreException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ CertStore certStore = (CertStore)iter.next();
+
+ certs.addAll(certStore.getCertificates(certSelect));
+ }
+
+ return certs;
+ }
+
+ /**
+ * Find the issuer certificate of the given certificate.
+ *
+ * @param cert the certificate hows issuer certificate should
+ * be found.
+ * @param certStores a list of <code>CertStore</code> object
+ * that will be searched
+ *
+ * @return then <code>X509Certificate</code> object containing
+ * the issuer certificate or <code>null</code> if not found
+ *
+ * @exception CertPathValidatorException if a TrustAnchor was
+ * found but the signature verificytion on the given certificate
+ * has thrown an exception. This Exception can be obtainted with
+ * <code>getCause()</code> method.
+ **/
+ private X509Certificate findIssuer(
+ X509Certificate cert,
+ List certStores)
+ throws CertPathValidatorException
+ {
+ Exception invalidKeyEx = null;
+ X509CertSelector certSelect = new X509CertSelector();
+ try
+ {
+ certSelect.setSubject(PrincipalUtil.getIssuerX509Principal(cert).getEncoded());
+ }
+ catch (CertificateEncodingException ex)
+ {
+ throw new CertPathValidatorException("Issuer not found", null, null, -1);
+ }
+ catch (IOException ex)
+ {
+ throw new CertPathValidatorException("Issuer not found", null, null, -1);
+ }
+
+ Iterator iter;
+ try
+ {
+ iter = findCertificates(certSelect, certStores).iterator();
+ }
+ catch (CertStoreException e)
+ {
+ throw new CertPathValidatorException(e);
+ }
+
+ X509Certificate issuer = null;
+ while (iter.hasNext() && issuer == null)
+ {
+ issuer = (X509Certificate)iter.next();
+ try
+ {
+ cert.verify(issuer.getPublicKey());
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ issuer = null;
+ }
+ }
+
+ if (issuer == null && invalidKeyEx == null)
+ {
+ throw new CertPathValidatorException("Issuer not found", null, null, -1);
+ }
+
+ if (issuer == null && invalidKeyEx != null)
+ {
+ throw new CertPathValidatorException("issuer found but certificate validation failed",invalidKeyEx,null,-1);
+ }
+
+ return issuer;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java
new file mode 100644
index 000000000..fef14a6be
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -0,0 +1,2182 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidatorSpi;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.PolicyQualifierInfo;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.TrustAnchor;
+import java.security.cert.PKIXParameters;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.BERConstructedOctetString;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralSubtree;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.NameConstraints;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extensions;
+
+/**
+ * CertPathValidatorSpi implemenation for X.509 Certificate validation ala rfc 3280<br />
+ **/
+public class PKIXCertPathValidatorSpi extends CertPathValidatorSpi
+{
+ private static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+ private static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+ private static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+ private static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+ private static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+ private static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+ private static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+ private static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+ private static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+ private static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+
+ private static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ private static final String ANY_POLICY = "2.5.29.32.0";
+
+
+ /*
+ * key usage bits
+ */
+ private static final int KEY_CERT_SIGN = 5;
+ private static final int CRL_SIGN = 6;
+
+ private static final String[] crlReasons = new String[] {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise" };
+
+ /**
+ * extract the value of the given extension, if it exists.
+ */
+ private ASN1Primitive getExtensionValue(
+ java.security.cert.X509Extension ext,
+ String oid)
+ throws AnnotatedException
+ {
+ byte[] bytes = ext.getExtensionValue(oid);
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ return getObject(oid, bytes);
+ }
+
+ private ASN1Primitive getObject(
+ String oid,
+ byte[] ext)
+ throws AnnotatedException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(ext);
+ ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
+
+ aIn = new ASN1InputStream(octs.getOctets());
+ return aIn.readObject();
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("exception processing extension " + oid, e);
+ }
+ }
+
+ private boolean withinDNSubtree(
+ ASN1Sequence dns,
+ ASN1Sequence subtree)
+ {
+ if (subtree.size() < 1)
+ {
+ return false;
+ }
+
+ if (subtree.size() > dns.size())
+ {
+ return false;
+ }
+
+ for (int j = subtree.size() - 1; j >= 0; j--)
+ {
+ if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void checkPermittedDN(
+ Set permitted,
+ ASN1Sequence dns)
+ throws CertPathValidatorException
+ {
+ if (permitted.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = permitted.iterator();
+
+ while (it.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+ if (withinDNSubtree(dns, subtree))
+ {
+ return;
+ }
+ }
+
+ throw new CertPathValidatorException("Subject distinguished name is not from a permitted subtree");
+ }
+
+ private void checkExcludedDN(
+ Set excluded,
+ ASN1Sequence dns)
+ throws CertPathValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+ if (withinDNSubtree(dns, subtree))
+ {
+ throw new CertPathValidatorException("Subject distinguished name is from an excluded subtree");
+ }
+ }
+ }
+
+ private Set intersectDN(
+ Set permitted,
+ ASN1Sequence dn)
+ {
+ if (permitted.isEmpty())
+ {
+ permitted.add(dn);
+
+ return permitted;
+ }
+ else
+ {
+ Set intersect = new HashSet();
+
+ Iterator _iter = permitted.iterator();
+ while (_iter.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)_iter.next();
+
+ if (withinDNSubtree(dn, subtree))
+ {
+ intersect.add(dn);
+ }
+ else if (withinDNSubtree(subtree, dn))
+ {
+ intersect.add(subtree);
+ }
+ }
+
+ return intersect;
+ }
+ }
+
+ private Set unionDN(
+ Set excluded,
+ ASN1Sequence dn)
+ {
+ if (excluded.isEmpty())
+ {
+ excluded.add(dn);
+
+ return excluded;
+ }
+ else
+ {
+ Set intersect = new HashSet();
+
+ Iterator _iter = excluded.iterator();
+ while (_iter.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)_iter.next();
+
+ if (withinDNSubtree(dn, subtree))
+ {
+ intersect.add(subtree);
+ }
+ else if (withinDNSubtree(subtree, dn))
+ {
+ intersect.add(dn);
+ }
+ else
+ {
+ intersect.add(subtree);
+ intersect.add(dn);
+ }
+ }
+
+ return intersect;
+ }
+ }
+
+ private Set intersectEmail(
+ Set permitted,
+ String email)
+ {
+ String _sub = email.substring(email.indexOf('@') + 1);
+
+ if (permitted.isEmpty())
+ {
+ permitted.add(_sub);
+
+ return permitted;
+ }
+ else
+ {
+ Set intersect = new HashSet();
+
+ Iterator _iter = permitted.iterator();
+ while (_iter.hasNext())
+ {
+ String _permitted = (String)_iter.next();
+
+ if (_sub.endsWith(_permitted))
+ {
+ intersect.add(_sub);
+ }
+ else if (_permitted.endsWith(_sub))
+ {
+ intersect.add(_permitted);
+ }
+ }
+
+ return intersect;
+ }
+ }
+
+ private Set unionEmail(
+ Set excluded,
+ String email)
+ {
+ String _sub = email.substring(email.indexOf('@') + 1);
+
+ if (excluded.isEmpty())
+ {
+ excluded.add(_sub);
+ return excluded;
+ }
+ else
+ {
+ Set intersect = new HashSet();
+
+ Iterator _iter = excluded.iterator();
+ while (_iter.hasNext())
+ {
+ String _excluded = (String)_iter.next();
+
+ if (_sub.endsWith(_excluded))
+ {
+ intersect.add(_excluded);
+ }
+ else if (_excluded.endsWith(_sub))
+ {
+ intersect.add(_sub);
+ }
+ else
+ {
+ intersect.add(_excluded);
+ intersect.add(_sub);
+ }
+ }
+
+ return intersect;
+ }
+ }
+
+ private Set intersectIP(
+ Set permitted,
+ byte[] ip)
+ {
+ // TBD
+ return permitted;
+ }
+
+ private Set unionIP(
+ Set excluded,
+ byte[] ip)
+ {
+ // TBD
+ return excluded;
+ }
+
+ private void checkPermittedEmail(
+ Set permitted,
+ String email)
+ throws CertPathValidatorException
+ {
+ if (permitted.isEmpty())
+ {
+ return;
+ }
+
+ String sub = email.substring(email.indexOf('@') + 1);
+ Iterator it = permitted.iterator();
+
+ while (it.hasNext())
+ {
+ String str = (String)it.next();
+
+ if (sub.endsWith(str))
+ {
+ return;
+ }
+ }
+
+ throw new CertPathValidatorException("Subject email address is not from a permitted subtree");
+ }
+
+ private void checkExcludedEmail(
+ Set excluded,
+ String email)
+ throws CertPathValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ String sub = email.substring(email.indexOf('@') + 1);
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ String str = (String)it.next();
+ if (sub.endsWith(str))
+ {
+ throw new CertPathValidatorException("Subject email address is from an excluded subtree");
+ }
+ }
+ }
+
+ private void checkPermittedIP(
+ Set permitted,
+ byte[] ip)
+ throws CertPathValidatorException
+ {
+ if (permitted.isEmpty())
+ {
+ return;
+ }
+
+ // TODO: ??? Something here
+ }
+
+ private void checkExcludedIP(
+ Set excluded,
+ byte[] ip)
+ throws CertPathValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ // TODO, check RFC791 and RFC1883 for IP bytes definition.
+ }
+
+ private PKIXPolicyNode removePolicyNode(
+ PKIXPolicyNode validPolicyTree,
+ List [] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
+
+ if (validPolicyTree == null)
+ {
+ return null;
+ }
+
+ if (_parent == null)
+ {
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ return null;
+ }
+ else
+ {
+ _parent.removeChild(_node);
+ removePolicyNodeRecurse(policyNodes, _node);
+
+ return validPolicyTree;
+ }
+ }
+
+ private void removePolicyNodeRecurse(
+ List [] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ policyNodes[_node.getDepth()].remove(_node);
+
+ if (_node.hasChildren())
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
+ removePolicyNodeRecurse(policyNodes, _child);
+ }
+ }
+ }
+
+ private boolean isSelfIssued(
+ X509Certificate cert)
+ {
+ return cert.getSubjectDN().equals(cert.getIssuerDN());
+ }
+
+ private boolean isAnyPolicy(
+ Set policySet)
+ {
+ return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
+ }
+
+ private AlgorithmIdentifier getAlgorithmIdentifier(
+ PublicKey key)
+ throws CertPathValidatorException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(
+ new ByteArrayInputStream(key.getEncoded()));
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ return info.getAlgorithmId();
+ }
+ catch (IOException e)
+ {
+ throw new CertPathValidatorException("exception processing public key");
+ }
+ }
+
+ private Set getQualifierSet(ASN1Sequence qualifiers)
+ throws CertPathValidatorException
+ {
+ Set pq = new HashSet();
+
+ if (qualifiers == null)
+ {
+ return pq;
+ }
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ Enumeration e = qualifiers.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
+ }
+ catch (IOException ex)
+ {
+ throw new CertPathValidatorException("exception building qualifier set: " + ex);
+ }
+
+ bOut.reset();
+ }
+
+ return pq;
+ }
+
+ private boolean processCertD1i(
+ int index,
+ List [] policyNodes,
+ DERObjectIdentifier pOid,
+ Set pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
+ Set expectedPolicies = node.getExpectedPolicies();
+
+ if (expectedPolicies.contains(pOid.getId()))
+ {
+ Set childExpectedPolicies = new HashSet();
+ childExpectedPolicies.add(pOid.getId());
+
+ PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ childExpectedPolicies,
+ node,
+ pq,
+ pOid.getId(),
+ false);
+ node.addChild(child);
+ policyNodes[index].add(child);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void processCertD1ii(
+ int index,
+ List [] policyNodes,
+ DERObjectIdentifier _poid,
+ Set _pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
+ Set _expectedPolicies = _node.getExpectedPolicies();
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Set _childExpectedPolicies = new HashSet();
+ _childExpectedPolicies.add(_poid.getId());
+
+ PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ _childExpectedPolicies,
+ _node,
+ _pq,
+ _poid.getId(),
+ false);
+ _node.addChild(_child);
+ policyNodes[index].add(_child);
+ return;
+ }
+ }
+ }
+
+ public CertPathValidatorResult engineValidate(
+ CertPath certPath,
+ CertPathParameters params)
+ throws CertPathValidatorException, InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXParameters))
+ {
+ throw new InvalidAlgorithmParameterException("params must be a PKIXParameters instance");
+ }
+
+ PKIXParameters paramsPKIX = (PKIXParameters)params;
+ if (paramsPKIX.getTrustAnchors() == null)
+ {
+ throw new InvalidAlgorithmParameterException("trustAnchors is null, this is not allowed for path validation");
+ }
+
+ //
+ // 6.1.1 - inputs
+ //
+
+ //
+ // (a)
+ //
+ List certs = certPath.getCertificates();
+ int n = certs.size();
+
+ if (certs.isEmpty())
+ {
+ throw new CertPathValidatorException("CertPath is empty", null, certPath, 0);
+ }
+
+ //
+ // (b)
+ //
+ Date validDate = getValidDate(paramsPKIX);
+
+ //
+ // (c)
+ //
+ Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
+
+ //
+ // (d)
+ //
+ TrustAnchor trust = findTrustAnchor((X509Certificate)certs.get(certs.size() - 1), certPath, certs.size() - 1, paramsPKIX.getTrustAnchors());
+
+ if (trust == null)
+ {
+ throw new CertPathValidatorException("TrustAnchor for CertPath not found.", null, certPath, -1);
+ }
+
+ //
+ // (e), (f), (g) are part of the paramsPKIX object.
+ //
+
+ Iterator certIter;
+ int index = 0;
+ int i;
+ //Certificate for each interation of the validation loop
+ //Signature information for each iteration of the validation loop
+ Set subTreeContraints = new HashSet();
+ Set subTreeExcludes = new HashSet();
+
+ //
+ // 6.1.2 - setup
+ //
+
+ //
+ // (a)
+ //
+ List [] policyNodes = new ArrayList[n + 1];
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ Set policySet = new HashSet();
+
+ policySet.add(ANY_POLICY);
+
+ PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(), ANY_POLICY, false);
+
+ policyNodes[0].add(validPolicyTree);
+
+ //
+ // (b)
+ //
+ Set permittedSubtreesDN = new HashSet();
+ Set permittedSubtreesEmail = new HashSet();
+ Set permittedSubtreesIP = new HashSet();
+
+ //
+ // (c)
+ //
+ Set excludedSubtreesDN = new HashSet();
+ Set excludedSubtreesEmail = new HashSet();
+ Set excludedSubtreesIP = new HashSet();
+
+ //
+ // (d)
+ //
+ int explicitPolicy;
+ Set acceptablePolicies = null;
+
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ //
+ // (e)
+ //
+ int inhibitAnyPolicy;
+
+ if (paramsPKIX.isAnyPolicyInhibited())
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ //
+ // (f)
+ //
+ int policyMapping;
+
+ if (paramsPKIX.isPolicyMappingInhibited())
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ //
+ // (g), (h), (i), (j)
+ //
+ PublicKey workingPublicKey;
+ X509Principal workingIssuerName;
+
+ X509Certificate sign = trust.getTrustedCert();
+ try
+ {
+ if (sign != null)
+ {
+ workingIssuerName = getSubjectPrincipal(sign);
+ workingPublicKey = sign.getPublicKey();
+ }
+ else
+ {
+ workingIssuerName = new X509Principal(trust.getCAName());
+ workingPublicKey = trust.getCAPublicKey();
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new CertPathValidatorException("TrustAnchor subjectDN: " + ex.toString());
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new CertPathValidatorException(ex.getMessage(), ex.getUnderlyingException(), certPath, index);
+ }
+
+ AlgorithmIdentifier workingAlgId = getAlgorithmIdentifier(workingPublicKey);
+ DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
+
+ //
+ // (k)
+ //
+ int maxPathLength = n;
+
+ //
+ // 6.1.3
+ //
+ Iterator tmpIter;
+ int tmpInt;
+
+ if (paramsPKIX.getTargetCertConstraints() != null
+ && !paramsPKIX.getTargetCertConstraints().match((X509Certificate)certs.get(0)))
+ {
+ throw new CertPathValidatorException("target certificate in certpath does not match targetcertconstraints", null, certPath, 0);
+ }
+
+
+ //
+ // initialise CertPathChecker's
+ //
+ List pathCheckers = paramsPKIX.getCertPathCheckers();
+ certIter = pathCheckers.iterator();
+ while (certIter.hasNext())
+ {
+ ((PKIXCertPathChecker)certIter.next()).init(false);
+ }
+
+ X509Certificate cert = null;
+
+ for (index = certs.size() - 1; index >= 0 ; index--)
+ {
+ try
+ {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialied the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate)certs.get(index);
+
+ //
+ // 6.1.3
+ //
+
+ //
+ // (a) verify
+ //
+ try
+ {
+ // (a) (1)
+ //
+ cert.verify(workingPublicKey, "SC");
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+ }
+
+ try
+ {
+ // (a) (2)
+ //
+ cert.checkValidity(validDate);
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new CertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new CertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+
+ //
+ // (a) (3)
+ //
+ if (paramsPKIX.isRevocationEnabled())
+ {
+ checkCRLs(paramsPKIX, cert, validDate, sign, workingPublicKey);
+ }
+
+ //
+ // (a) (4) name chaining
+ //
+ if (!getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
+ {
+ throw new CertPathValidatorException(
+ "IssuerName(" + getEncodedIssuerPrincipal(cert) +
+ ") does not match SubjectName(" + workingIssuerName +
+ ") of signing certificate", null, certPath, index);
+ }
+
+ //
+ // (b), (c) permitted and excluded subtree checking.
+ //
+ if (!(isSelfIssued(cert) && (i < n)))
+ {
+ X509Principal principal = getSubjectPrincipal(cert);
+ ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(principal.getEncoded()));
+ ASN1Sequence dns;
+
+ try
+ {
+ dns = (ASN1Sequence)aIn.readObject();
+ }
+ catch (IOException e)
+ {
+ throw new CertPathValidatorException("exception extracting subject name when checking subtrees");
+ }
+
+ checkPermittedDN(permittedSubtreesDN, dns);
+
+ checkExcludedDN(excludedSubtreesDN, dns);
+
+ ASN1Sequence altName = (ASN1Sequence)getExtensionValue(cert, SUBJECT_ALTERNATIVE_NAME);
+ if (altName != null)
+ {
+ for (int j = 0; j < altName.size(); j++)
+ {
+ ASN1TaggedObject o = (ASN1TaggedObject)altName.getObjectAt(j);
+
+ switch(o.getTagNo())
+ {
+ case 1:
+ String email = DERIA5String.getInstance(o, true).getString();
+
+ checkPermittedEmail(permittedSubtreesEmail, email);
+ checkExcludedEmail(excludedSubtreesEmail, email);
+ break;
+ case 4:
+ ASN1Sequence altDN = ASN1Sequence.getInstance(o, true);
+
+ checkPermittedDN(permittedSubtreesDN, altDN);
+ checkExcludedDN(excludedSubtreesDN, altDN);
+ break;
+ case 7:
+ byte[] ip = ASN1OctetString.getInstance(o, true).getOctets();
+
+ checkPermittedIP(permittedSubtreesIP, ip);
+ checkExcludedIP(excludedSubtreesIP, ip);
+ }
+ }
+ }
+ }
+
+ //
+ // (d) policy Information checking against initial policy and
+ // policy mapping
+ //
+ ASN1Sequence certPolicies = (ASN1Sequence)getExtensionValue(cert, CERTIFICATE_POLICIES);
+ if (certPolicies != null && validPolicyTree != null)
+ {
+ //
+ // (d) (1)
+ //
+ Enumeration e = certPolicies.getObjects();
+ Set pols = new HashSet();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+ DERObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+ pols.add(pOid.getId());
+
+ if (!ANY_POLICY.equals(pOid.getId()))
+ {
+ Set pq = getQualifierSet(pInfo.getPolicyQualifiers());
+
+ boolean match = processCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ processCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies == null || acceptablePolicies.contains(ANY_POLICY))
+ {
+ acceptablePolicies = pols;
+ }
+ else
+ {
+ Iterator it = acceptablePolicies.iterator();
+ Set t1 = new HashSet();
+
+ while (it.hasNext())
+ {
+ Object o = it.next();
+
+ if (pols.contains(o))
+ {
+ t1.add(o);
+ }
+ }
+
+ acceptablePolicies = t1;
+ }
+
+ //
+ // (d) (2)
+ //
+ if ((inhibitAnyPolicy > 0) || ((i < n) && isSelfIssued(cert)))
+ {
+ e = certPolicies.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+ if (ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+ {
+ Set _apq = getQualifierSet(pInfo.getPolicyQualifiers());
+ List _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k);
+
+ Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+ while (_policySetIter.hasNext())
+ {
+ Object _tmp = _policySetIter.next();
+
+ String _policy;
+ if (_tmp instanceof String)
+ {
+ _policy = (String)_tmp;
+ }
+ else if (_tmp instanceof DERObjectIdentifier)
+ {
+ _policy = ((DERObjectIdentifier)_tmp).getId();
+ }
+ else
+ {
+ continue;
+ }
+
+ boolean _found = false;
+ Iterator _childrenIter = _node.getChildren();
+
+ while (_childrenIter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next();
+
+ if (_policy.equals(_child.getValidPolicy()))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ Set _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.add(_policy);
+
+ PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(),
+ i,
+ _newChildExpectedPolicies,
+ _node,
+ _apq,
+ _policy,
+ false);
+ _node.addChild(_newChild);
+ policyNodes[i].add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensionOids != null)
+ {
+ boolean critical = criticalExtensionOids.contains(CERTIFICATE_POLICIES);
+
+ List nodes = policyNodes[i];
+ for (int j = 0; j < nodes.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j);
+ node.setCritical(critical);
+ }
+ }
+ }
+
+ //
+ // (e)
+ //
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+
+ //
+ // (f)
+ //
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ throw new CertPathValidatorException("No valid policy tree found when one expected.");
+ }
+
+ //
+ // 6.1.4
+ //
+
+ if (i != n)
+ {
+ if (cert != null && cert.getVersion() == 1)
+ {
+ throw new CertPathValidatorException(
+ "Version 1 certs can't be used as CA ones");
+ }
+
+ //
+ //
+ // (a) check the policy mappings
+ //
+ ASN1Primitive pm = getExtensionValue(cert, POLICY_MAPPINGS);
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence)pm;
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+
+ DERObjectIdentifier issuerDomainPolicy = (DERObjectIdentifier)mapping.getObjectAt(0);
+ DERObjectIdentifier subjectDomainPolicy = (DERObjectIdentifier)mapping.getObjectAt(1);
+
+ if (ANY_POLICY.equals(issuerDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy");
+ }
+
+ if (ANY_POLICY.equals(subjectDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy");
+ }
+ }
+ }
+
+ // (b)
+ //
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence)pm;
+ Map m_idp = new HashMap();
+ Set s_idp = new HashSet();
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+ String id_p = ((DERObjectIdentifier)mapping.getObjectAt(0)).getId();
+ String sd_p = ((DERObjectIdentifier)mapping.getObjectAt(1)).getId();
+ Set tmp;
+
+ if (!m_idp.containsKey(id_p))
+ {
+ tmp = new HashSet();
+ tmp.add(sd_p);
+ m_idp.put(id_p, tmp);
+ s_idp.add(id_p);
+ }
+ else
+ {
+ tmp = (Set)m_idp.get(id_p);
+ tmp.add(sd_p);
+ }
+ }
+
+ Iterator it_idp = s_idp.iterator();
+ while (it_idp.hasNext())
+ {
+ String id_p = (String)it_idp.next();
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = (ASN1Sequence)getExtensionValue(
+ cert, CERTIFICATE_POLICIES);
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = PolicyInformation.getInstance(e.nextElement());
+ if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ pq = getQualifierSet(pinfo.getPolicyQualifiers());
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(
+ new ArrayList(), i,
+ (Set)m_idp.get(id_p),
+ p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) handle the name constraints extension
+ //
+ ASN1Sequence ncSeq = (ASN1Sequence)getExtensionValue(cert, NAME_CONSTRAINTS);
+ if (ncSeq != null)
+ {
+ NameConstraints nc = NameConstraints.getInstance(ncSeq);
+
+ //
+ // (g) (1) permitted subtrees
+ //
+ GeneralSubtree[] permitted = nc.getPermittedSubtrees();
+ if (permitted != null)
+ {
+ for (int indx = 0; indx != permitted.length; indx++)
+ {
+ GeneralSubtree subtree = permitted[indx];
+ GeneralName base = subtree.getBase();
+
+ switch(base.getTagNo())
+ {
+ case 1:
+ permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString());
+ break;
+ case 4:
+ permittedSubtreesDN = intersectDN(permittedSubtreesDN, (ASN1Sequence)base.getName());
+ break;
+ case 7:
+ permittedSubtreesIP = intersectIP(permittedSubtreesIP, BERConstructedOctetString.fromSequence((ASN1Sequence)base.getName()).getOctets());
+ break;
+ }
+ }
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ GeneralSubtree[] excluded = nc.getExcludedSubtrees();
+ if (excluded != null)
+ {
+ for (int indx = 0; indx != excluded.length; indx++)
+ {
+ GeneralSubtree subtree = excluded[indx];
+ GeneralName base = subtree.getBase();
+
+ switch(base.getTagNo())
+ {
+ case 1:
+ excludedSubtreesEmail = unionEmail(excludedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString());
+ break;
+ case 4:
+ excludedSubtreesDN = unionDN(excludedSubtreesDN, (ASN1Sequence)base.getName());
+ break;
+ case 7:
+ excludedSubtreesIP = unionIP(excludedSubtreesIP, BERConstructedOctetString.fromSequence((ASN1Sequence)base.getName()).getOctets());
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // (h)
+ //
+ if (!isSelfIssued(cert))
+ {
+ //
+ // (1)
+ //
+ if (explicitPolicy != 0)
+ {
+ explicitPolicy--;
+ }
+
+ //
+ // (2)
+ //
+ if (policyMapping != 0)
+ {
+ policyMapping--;
+ }
+
+ //
+ // (3)
+ //
+ if (inhibitAnyPolicy != 0)
+ {
+ inhibitAnyPolicy--;
+ }
+ }
+
+ //
+ // (i)
+ //
+ ASN1Sequence pc = (ASN1Sequence)getExtensionValue(cert, POLICY_CONSTRAINTS);
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+ if (tmpInt < explicitPolicy)
+ {
+ explicitPolicy = tmpInt;
+ }
+ break;
+ case 1:
+ tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+ if (tmpInt < policyMapping)
+ {
+ policyMapping = tmpInt;
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (j)
+ //
+ DERInteger iap = (DERInteger)getExtensionValue(cert, INHIBIT_ANY_POLICY);
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.getValue().intValue();
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ {
+ inhibitAnyPolicy = _inhibitAnyPolicy;
+ }
+ }
+
+ //
+ // (k)
+ //
+ BasicConstraints bc = BasicConstraints.getInstance(
+ getExtensionValue(cert, BASIC_CONSTRAINTS));
+ if (bc != null)
+ {
+ if (!(bc.isCA()))
+ {
+ throw new CertPathValidatorException("Not a CA certificate");
+ }
+ }
+ else
+ {
+ throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+ }
+
+ //
+ // (l)
+ //
+ if (!isSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ throw new CertPathValidatorException("Max path length not greater than zero");
+ }
+
+ maxPathLength--;
+ }
+
+ //
+ // (m)
+ //
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.intValue();
+
+ if (_plc < maxPathLength)
+ {
+ maxPathLength = _plc;
+ }
+ }
+ }
+
+ //
+ // (n)
+ //
+ boolean[] _usage = cert.getKeyUsage();
+
+ if ((_usage != null) && !_usage[5])
+ {
+ throw new CertPathValidatorException(
+ "Issuer certificate keyusage extension is critical an does not permit key signing.\n",
+ null, certPath, index);
+ }
+
+ //
+ // (o)
+ //
+ Set criticalExtensions = new HashSet(cert.getCriticalExtensionOIDs());
+ // these extensions are handle by the algorithem
+ criticalExtensions.remove(KEY_USAGE);
+ criticalExtensions.remove(CERTIFICATE_POLICIES);
+ criticalExtensions.remove(POLICY_MAPPINGS);
+ criticalExtensions.remove(INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(POLICY_CONSTRAINTS);
+ criticalExtensions.remove(BASIC_CONSTRAINTS);
+ criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(NAME_CONSTRAINTS);
+
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+ }
+ }
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new CertPathValidatorException(
+ "Certificate has unsupported critical extension", null, certPath, index);
+ }
+ }
+
+ // set signing certificate for next round
+ sign = cert;
+ workingPublicKey = sign.getPublicKey();
+ try
+ {
+ workingIssuerName = getSubjectPrincipal(sign);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new CertPathValidatorException(sign.getSubjectDN().getName() + " :" + ex.toString());
+ }
+ workingAlgId = getAlgorithmIdentifier(workingPublicKey);
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, index);
+ }
+ }
+
+ //
+ // 6.1.5 Wrap-up procedure
+ //
+
+ //
+ // (a)
+ //
+ if (!isSelfIssued(cert) && (explicitPolicy != 0))
+ {
+ explicitPolicy--;
+ }
+
+ //
+ // (b)
+ //
+ try
+ {
+ ASN1Sequence pc = (ASN1Sequence)getExtensionValue(cert, POLICY_CONSTRAINTS);
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+ if (tmpInt == 0)
+ {
+ explicitPolicy = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, index);
+ }
+
+ //
+ // (c) (d) and (e) are already done
+ //
+
+ //
+ // (f)
+ //
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ // these extensions are handle by the algorithm
+ criticalExtensions.remove(KEY_USAGE);
+ criticalExtensions.remove(CERTIFICATE_POLICIES);
+ criticalExtensions.remove(POLICY_MAPPINGS);
+ criticalExtensions.remove(INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(POLICY_CONSTRAINTS);
+ criticalExtensions.remove(BASIC_CONSTRAINTS);
+ criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(NAME_CONSTRAINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+ }
+ }
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new CertPathValidatorException(
+ "Certificate has unsupported critical extension", null, certPath, index);
+ }
+
+ //
+ // (g)
+ //
+ PKIXPolicyNode intersection;
+
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ throw new CertPathValidatorException("Explicit policy requested but none available.");
+ }
+ intersection = null;
+ }
+ else if (isAnyPolicy(userInitialPolicySet)) // (g) (ii)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ if (acceptablePolicies.isEmpty())
+ {
+ throw new CertPathValidatorException("Explicit policy requested but none available.");
+ }
+ else
+ {
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ _validPolicyNodeSet.add(_iter.next());
+ }
+ }
+ }
+ }
+
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!acceptablePolicies.contains(_validPolicy))
+ {
+ //validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in RFC3280.
+ // However, as far as the validation result is concerned, both produce
+ // adequate result. The only difference is whether AnyPolicy is remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+ if (!ANY_POLICY.equals(_c_node.getValidPolicy()))
+ {
+ _validPolicyNodeSet.add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!userInitialPolicySet.contains(_validPolicy))
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+
+ if ((explicitPolicy > 0) || (intersection != null))
+ {
+ return new PKIXCertPathValidatorResult(trust, intersection, workingPublicKey);
+ }
+
+ throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+ }
+
+ private Date getValidDate(
+ PKIXParameters paramsPKIX)
+ {
+ Date validDate = paramsPKIX.getDate();
+
+ if (validDate == null)
+ {
+ validDate = new Date();
+ }
+
+ return validDate;
+ }
+
+ private void checkCRLs(PKIXParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate sign, PublicKey workingPublicKey)
+ throws AnnotatedException
+ {
+ X509CRLSelector crlselect;
+ crlselect = new X509CRLSelector();
+
+ try
+ {
+ crlselect.addIssuerName(getEncodedIssuerPrincipal(cert).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from certificate: " + e, e);
+ }
+
+ crlselect.setCertificateChecking(cert);
+
+ Iterator crl_iter = findCRLs(crlselect, paramsPKIX.getCertStores()).iterator();
+ boolean validCrlFound = false;
+ X509CRLEntry crl_entry;
+ while (crl_iter.hasNext())
+ {
+ X509CRL crl = (X509CRL)crl_iter.next();
+
+ if (cert.getNotAfter().after(crl.getThisUpdate()))
+ {
+ if (crl.getNextUpdate() == null
+ || validDate.before(crl.getNextUpdate()))
+ {
+ validCrlFound = true;
+ }
+
+ if (sign != null)
+ {
+ boolean[] keyusage = sign.getKeyUsage();
+
+ if (keyusage != null
+ && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+ {
+ throw new AnnotatedException(
+ "Issuer certificate keyusage extension does not permit crl signing.\n" + sign);
+ }
+ }
+
+ try
+ {
+ crl.verify(workingPublicKey, "SC");
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("can't verify CRL: " + e, e);
+ }
+
+ crl_entry = crl.getRevokedCertificate(cert.getSerialNumber());
+ if (crl_entry != null
+ && !validDate.before(crl_entry.getRevocationDate()))
+ {
+ String reason = null;
+
+ if (crl_entry.hasExtensions())
+ {
+ DEREnumerated reasonCode = DEREnumerated.getInstance(getExtensionValue(crl_entry, X509Extensions.ReasonCode.getId()));
+ if (reasonCode != null)
+ {
+ reason = crlReasons[reasonCode.getValue().intValue()];
+ }
+ }
+
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
+ df.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String message = "Certificate revocation after " + df.format(crl_entry.getRevocationDate());
+
+ if (reason != null)
+ {
+ message += ", reason: " + reason;
+ }
+
+ throw new AnnotatedException(message);
+ }
+
+ //
+ // check the DeltaCRL indicator, base point and the issuing distribution point
+ //
+ ASN1Primitive idp = getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+ ASN1Primitive dci = getExtensionValue(crl, DELTA_CRL_INDICATOR);
+
+ if (dci != null)
+ {
+ X509CRLSelector baseSelect = new X509CRLSelector();
+
+ try
+ {
+ baseSelect.addIssuerName(getIssuerPrincipal(crl).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("can't extract issuer from certificate: " + e, e);
+ }
+
+ baseSelect.setMinCRLNumber(((DERInteger)dci).getPositiveValue());
+ baseSelect.setMaxCRLNumber(((DERInteger)getExtensionValue(crl, CRL_NUMBER)).getPositiveValue().subtract(BigInteger.valueOf(1)));
+
+ boolean foundBase = false;
+ Iterator it = findCRLs(baseSelect, paramsPKIX.getCertStores()).iterator();
+ while (it.hasNext())
+ {
+ X509CRL base = (X509CRL)it.next();
+
+ ASN1Primitive baseIdp = getExtensionValue(base, ISSUING_DISTRIBUTION_POINT);
+
+ if (idp == null)
+ {
+ if (baseIdp == null)
+ {
+ foundBase = true;
+ break;
+ }
+ }
+ else
+ {
+ if (idp.equals(baseIdp))
+ {
+ foundBase = true;
+ break;
+ }
+ }
+ }
+
+ if (!foundBase)
+ {
+ throw new AnnotatedException("No base CRL for delta CRL");
+ }
+ }
+
+ if (idp != null)
+ {
+ IssuingDistributionPoint p = IssuingDistributionPoint.getInstance(idp);
+ BasicConstraints bc = BasicConstraints.getInstance(getExtensionValue(cert, BASIC_CONSTRAINTS));
+
+ if (p.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+ {
+ throw new AnnotatedException("CA Cert CRL only contains user certificates");
+ }
+
+ if (p.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+ {
+ throw new AnnotatedException("End CRL only contains CA certificates");
+ }
+
+ if (p.onlyContainsAttributeCerts())
+ {
+ throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted");
+ }
+ }
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ throw new AnnotatedException("no valid CRL found");
+ }
+ }
+
+ /**
+ * Return a Collection of all CRLs found in the
+ * CertStore's that are matching the crlSelect criteriums.
+ *
+ * @param certSelector a {@link CertSelector CertSelector}
+ * object that will be used to select the certificates
+ * @param certStores a List containing only {@link CertStore
+ * CertStore} objects. These are used to search for
+ * CRLs
+ *
+ * @return a Collection of all found {@link CRL CRL}
+ * objects. May be empty but never <code>null</code>.
+ */
+ private Collection findCRLs(
+ X509CRLSelector crlSelect,
+ List crlStores)
+ throws AnnotatedException
+ {
+ Set crls = new HashSet();
+ Iterator iter = crlStores.iterator();
+
+ while (iter.hasNext())
+ {
+ CertStore certStore = (CertStore)iter.next();
+
+ try
+ {
+ crls.addAll(certStore.getCRLs(crlSelect));
+ }
+ catch (CertStoreException e)
+ {
+ throw new AnnotatedException("cannot extract crl: " + e, e);
+ }
+ }
+
+ return crls;
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the fiven X509 certificate.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ *
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ *
+ * @exception CertPathValidatorException if a TrustAnchor was
+ * found but the signature verification on the given certificate
+ * has thrown an exception. This Exception can be obtainted with
+ * <code>getCause()</code> method.
+ **/
+ final TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ CertPath certPath,
+ int index,
+ Set trustAnchors)
+ throws CertPathValidatorException
+ {
+ Iterator iter = trustAnchors.iterator();
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+
+ try
+ {
+ certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new CertPathValidatorException(ex);
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new CertPathValidatorException(ex.getUnderlyingException());
+ }
+
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X509Principal certIssuer = getEncodedIssuerPrincipal(cert);
+ X509Principal caName = new X509Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new CertPathValidatorException(ex.getMessage(), ex.getUnderlyingException(), certPath, index);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ cert.verify(trustPublicKey);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new CertPathValidatorException("TrustAnchor found but certificate validation failed.", invalidKeyEx, certPath, index);
+ }
+
+ return trust;
+ }
+
+ private X509Principal getIssuerPrincipal(X509CRL crl)
+ throws AnnotatedException
+ {
+ try
+ {
+ return PrincipalUtil.getIssuerX509Principal(crl);
+ }
+ catch (CRLException e)
+ {
+ throw new AnnotatedException("can't get CRL issuer principal", e);
+ }
+ }
+
+ private X509Principal getEncodedIssuerPrincipal(X509Certificate cert)
+ throws AnnotatedException
+ {
+ try
+ {
+ return PrincipalUtil.getIssuerX509Principal(cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new AnnotatedException("can't get issuer principal.", e);
+ }
+ }
+
+ private X509Principal getSubjectPrincipal(X509Certificate cert)
+ throws AnnotatedException
+ {
+ try
+ {
+ return PrincipalUtil.getSubjectX509Principal(cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new AnnotatedException("can't get subject principal.", e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXPolicyNode.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXPolicyNode.java
new file mode 100644
index 000000000..9cb2fbbfd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/PKIXPolicyNode.java
@@ -0,0 +1,167 @@
+package org.spongycastle.jce.provider;
+
+import java.security.cert.PolicyNode;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+public class PKIXPolicyNode
+ implements PolicyNode
+{
+ protected List children;
+ protected int depth;
+ protected Set expectedPolicies;
+ protected PolicyNode parent;
+ protected Set policyQualifiers;
+ protected String validPolicy;
+ protected boolean critical;
+
+ /*
+ *
+ * CONSTRUCTORS
+ *
+ */
+
+ public PKIXPolicyNode(
+ List _children,
+ int _depth,
+ Set _expectedPolicies,
+ PolicyNode _parent,
+ Set _policyQualifiers,
+ String _validPolicy,
+ boolean _critical)
+ {
+ children = _children;
+ depth = _depth;
+ expectedPolicies = _expectedPolicies;
+ parent = _parent;
+ policyQualifiers = _policyQualifiers;
+ validPolicy = _validPolicy;
+ critical = _critical;
+ }
+
+ public void addChild(
+ PKIXPolicyNode _child)
+ {
+ children.add(_child);
+ _child.setParent(this);
+ }
+
+ public Iterator getChildren()
+ {
+ return children.iterator();
+ }
+
+ public int getDepth()
+ {
+ return depth;
+ }
+
+ public Set getExpectedPolicies()
+ {
+ return expectedPolicies;
+ }
+
+ public PolicyNode getParent()
+ {
+ return parent;
+ }
+
+ public Set getPolicyQualifiers()
+ {
+ return policyQualifiers;
+ }
+
+ public String getValidPolicy()
+ {
+ return validPolicy;
+ }
+
+ public boolean hasChildren()
+ {
+ return !children.isEmpty();
+ }
+
+ public boolean isCritical()
+ {
+ return critical;
+ }
+
+ public void removeChild(PKIXPolicyNode _child)
+ {
+ children.remove(_child);
+ }
+
+ public void setCritical(boolean _critical)
+ {
+ critical = _critical;
+ }
+
+ public void setParent(PKIXPolicyNode _parent)
+ {
+ parent = _parent;
+ }
+
+ public String toString()
+ {
+ return toString("");
+ }
+
+ public String toString(String _indent)
+ {
+ StringBuffer _buf = new StringBuffer();
+ _buf.append(_indent);
+ _buf.append(validPolicy);
+ _buf.append(" {\n");
+
+ for(int i = 0; i < children.size(); i++) {
+ _buf.append(((PKIXPolicyNode)children.get(i)).toString(_indent + " "));
+ }
+
+ _buf.append(_indent);
+ _buf.append("}\n");
+ return _buf.toString();
+ }
+
+ public Object clone()
+ {
+ return copy();
+ }
+
+ public PKIXPolicyNode copy()
+ {
+ HashSet _expectedPolicies = new HashSet();
+ Iterator _iter = expectedPolicies.iterator();
+ while (_iter.hasNext())
+ {
+ _expectedPolicies.add(new String((String)_iter.next()));
+ }
+
+ HashSet _policyQualifiers = new HashSet();
+ _iter = policyQualifiers.iterator();
+ while (_iter.hasNext())
+ {
+ _policyQualifiers.add(new String((String)_iter.next()));
+ }
+
+ PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(),
+ depth,
+ _expectedPolicies,
+ null,
+ _policyQualifiers,
+ new String(validPolicy),
+ critical);
+
+ _iter = children.iterator();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy();
+ _child.setParent(_node);
+ _node.addChild(_child);
+ }
+
+ return _node;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/ProviderUtil.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/ProviderUtil.java
new file mode 100644
index 000000000..a67007e6d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/ProviderUtil.java
@@ -0,0 +1,47 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ProviderUtil
+{
+ private static final long MAX_MEMORY = Integer.MAX_VALUE;
+
+ private static volatile ECParameterSpec ecImplicitCaParams;
+
+ static void setParameter(String parameterName, Object parameter)
+ {
+ if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+ {
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ ecImplicitCaParams = (ECParameterSpec)parameter;
+ }
+ }
+ }
+
+ public static ECParameterSpec getEcImplicitlyCa()
+ {
+ return ecImplicitCaParams;
+ }
+
+ static int getReadLimit(InputStream in)
+ throws IOException
+ {
+ if (in instanceof ByteArrayInputStream)
+ {
+ return in.available();
+ }
+
+ if (MAX_MEMORY > Integer.MAX_VALUE)
+ {
+ return Integer.MAX_VALUE;
+ }
+
+ return (int)MAX_MEMORY;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java
new file mode 100644
index 000000000..2be3e0c28
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -0,0 +1,87 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509Extension;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.GeneralSubtree;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.NameConstraints;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.util.Arrays;
+
+public class RFC3280CertPathUtilities
+{
+ public static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+
+ public static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+
+ public static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+
+ public static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+
+ public static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+
+ public static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+
+ public static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+
+ public static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+
+ public static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+
+ public static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+
+ public static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+
+ public static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ public static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+
+ public static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ public static final String ANY_POLICY = "2.5.29.32.0";
+
+ /*
+ * key usage bits
+ */
+ public static final int KEY_CERT_SIGN = 5;
+
+ public static final int CRL_SIGN = 6;
+
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/X509CRLObject.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/X509CRLObject.java
new file mode 100644
index 000000000..b31938bd7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/X509CRLObject.java
@@ -0,0 +1,554 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLNumber;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+public class X509CRLObject
+ extends X509CRL
+{
+ private CertificateList c;
+ private String sigAlgName;
+ private byte[] sigAlgParams;
+ private boolean isIndirect;
+
+ static boolean isIndirectCRL(X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+ return idp != null
+ && IssuingDistributionPoint.getInstance(X509ExtensionUtil.fromExtensionValue(idp)).isIndirectCRL();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCRLException(
+ "Exception reading IssuingDistributionPoint", e);
+ }
+ }
+
+ public X509CRLObject(
+ CertificateList c)
+ throws CRLException
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = isIndirectCRL(this);
+ }
+ catch (Exception e)
+ {
+ throw new CRLException("CRL contents invalid: " + e);
+ }
+ }
+
+ /**
+ * Will return true if any extensions are present and marked
+ * as critical as we currently dont handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ if (extns == null)
+ {
+ return false;
+ }
+
+ extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+ return !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ if (this.getVersion() == 2)
+ {
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertList().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ verify(key, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+ {
+ throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+ }
+
+ Signature sig;
+
+ if (sigProvider != null)
+ {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+ else
+ {
+ sig = Signature.getInstance(getSigAlgName());
+ }
+
+ sig.initVerify(key);
+ sig.update(this.getTBSCertList());
+
+ if (!sig.verify(this.getSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public Principal getIssuerDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+ }
+
+ public Date getThisUpdate()
+ {
+ return c.getThisUpdate().getDate();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (c.getNextUpdate() != null)
+ {
+ return c.getNextUpdate().getDate();
+ }
+
+ return null;
+ }
+
+ private Set loadCRLEntries()
+ {
+ Set entrySet = new HashSet();
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+ X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ entrySet.add(crlEntry);
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return entrySet;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+ {
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+ if (serialNumber.equals(entry.getUserCertificate().getValue()))
+ {
+ return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getRevokedCertificates()
+ {
+ Set entrySet = loadCRLEntries();
+
+ if (!entrySet.isEmpty())
+ {
+ return Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public byte[] getTBSCertList()
+ throws CRLException
+ {
+ try
+ {
+ return c.getTBSCertList().getEncoded("DER");
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ public String getSigAlgName()
+ {
+ return sigAlgName;
+ }
+
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ {
+ byte[] tmp = new byte[sigAlgParams.length];
+
+ System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" Version: ").append(this.getVersion()).append(
+ nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN())
+ .append(nl);
+ buf.append(" This update: ").append(this.getThisUpdate())
+ .append(nl);
+ buf.append(" Next update: ").append(this.getNextUpdate())
+ .append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName())
+ .append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(
+ new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: ").append(nl);
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(
+ ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.cRLNumber))
+ {
+ buf.append(
+ new CRLNumber(DERInteger.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid.equals(Extension.deltaCRLIndicator))
+ {
+ buf.append(
+ "Base CRL: "
+ + new CRLNumber(DERInteger.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid
+ .equals(Extension.issuingDistributionPoint))
+ {
+ buf.append(
+ IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid
+ .equals(Extension.cRLDistributionPoints))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.freshestCRL))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(
+ ASN1Dump.dumpAsString(dIn.readObject()))
+ .append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ Set set = getRevokedCertificates();
+ if (set != null)
+ {
+ Iterator it = set.iterator();
+ while (it.hasNext())
+ {
+ buf.append(it.next());
+ buf.append(nl);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!cert.getType().equals("X.509"))
+ {
+ throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+ }
+
+ TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+
+ X500Name caName = c.getIssuer();
+
+ if (certs != null)
+ {
+ BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+ for (int i = 0; i < certs.length; i++)
+ {
+ if (isIndirect && certs[i].hasExtensions())
+ {
+ Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+
+ if (certs[i].getUserCertificate().getValue().equals(serial))
+ {
+ X500Name issuer;
+
+ try
+ {
+ issuer = org.spongycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new RuntimeException("Cannot process certificate");
+ }
+
+ if (!caName.equals(issuer))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/X509CertificateObject.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/X509CertificateObject.java
new file mode 100644
index 000000000..cd1c6d7c9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/jce/provider/X509CertificateObject.java
@@ -0,0 +1,856 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.misc.NetscapeRevocationURL;
+import org.spongycastle.asn1.misc.VerisignCzagExtension;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.encoders.Hex;
+
+public class X509CertificateObject
+ extends X509Certificate
+ implements PKCS12BagAttributeCarrier
+{
+ private org.spongycastle.asn1.x509.Certificate c;
+ private BasicConstraints basicConstraints;
+ private boolean[] keyUsage;
+ private boolean hashValueSet;
+ private int hashValue;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ public X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate c)
+ throws CertificateParsingException
+ {
+ this.c = c;
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.19");
+
+ if (bytes != null)
+ {
+ basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.15");
+ if (bytes != null)
+ {
+ DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+ bytes = bits.getBytes();
+ int length = (bytes.length * 8) - bits.getPadBits();
+
+ keyUsage = new boolean[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+ keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility
+ {
+ throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+ }
+
+ if (date.getTime() < this.getNotBefore().getTime())
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getSerialNumber().getValue();
+ }
+
+ public Principal getIssuerDN()
+ {
+ try
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public Principal getSubjectDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+ }
+
+ public Date getNotBefore()
+ {
+ return c.getStartDate().getDate();
+ }
+
+ public Date getNotAfter()
+ {
+ return c.getEndDate().getDate();
+ }
+
+ public byte[] getTBSCertificate()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ /**
+ * return a more "meaningful" representation for the signature algorithm used in
+ * the certficate.
+ */
+ public String getSigAlgName()
+ {
+ Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ if (prov != null)
+ {
+ String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ Provider[] provs = Security.getProviders();
+
+ //
+ // search every provider looking for a real algorithm
+ //
+ for (int i = 0; i != provs.length; i++)
+ {
+ String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ return this.getSigAlgOID();
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getSigAlgParams()
+ {
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ try
+ {
+ return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getIssuerUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getSubjectUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ return keyUsage;
+ }
+
+ public List getExtendedKeyUsage()
+ throws CertificateParsingException
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.37");
+
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension");
+ }
+ }
+
+ return null;
+ }
+
+ public int getBasicConstraints()
+ {
+ if (basicConstraints != null)
+ {
+ if (basicConstraints.isCA())
+ {
+ if (basicConstraints.getPathLenConstraint() == null)
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return basicConstraints.getPathLenConstraint().intValue();
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ public Collection getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+ }
+
+ public Collection getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getExtensionBytes(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+ if (ext != null)
+ {
+ return ext.getExtnValue().getOctets();
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (!ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ if (this.getVersion() == 3)
+ {
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ String oidId = oid.getId();
+
+ if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
+ || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
+ || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
+ || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
+ || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
+ || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
+ || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
+ {
+ continue;
+ }
+
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ try
+ {
+ return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ return null; // should never happen...
+ }
+ }
+
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof Certificate))
+ {
+ return false;
+ }
+
+ Certificate other = (Certificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public synchronized int hashCode()
+ {
+ if (!hashValueSet)
+ {
+ hashValue = calculateHashCode();
+ hashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ private int calculateHashCode()
+ {
+ try
+ {
+ int hashCode = 0;
+ byte[] certData = this.getEncoded();
+ for (int i = 1; i < certData.length; i++)
+ {
+ hashCode += certData[i] * i;
+ }
+ return hashCode;
+ }
+ catch (CertificateEncodingException e)
+ {
+ return 0;
+ }
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" [0] Version: ").append(this.getVersion()).append(nl);
+ buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl);
+ buf.append(" Start Date: ").append(this.getNotBefore()).append(nl);
+ buf.append(" Final Date: ").append(this.getNotAfter()).append(nl);
+ buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl);
+ buf.append(" Public Key: ").append(this.getPublicKey()).append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: \n");
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.basicConstraints))
+ {
+ buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.keyUsage))
+ {
+ buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+ {
+ buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+ {
+ buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+ {
+ buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ //buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public final void verify(
+ PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature;
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ try
+ {
+ signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ signature = Signature.getInstance(sigName);
+ }
+
+ checkSignature(key, signature);
+ }
+
+ public final void verify(
+ PublicKey key,
+ String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+ Signature signature = Signature.getInstance(sigName, sigProvider);
+
+ checkSignature(key, signature);
+ }
+
+ private void checkSignature(
+ PublicKey key,
+ Signature signature)
+ throws CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException
+ {
+ if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+ // TODO This should go after the initVerify?
+ X509SignatureUtil.setSignatureParameters(signature, params);
+
+ signature.initVerify(key);
+
+ signature.update(this.getTBSCertificate());
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new SignatureException("certificate does not verify with supplied key");
+ }
+ }
+
+ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+ {
+ return false;
+ }
+
+ if (id1.getParameters() == null)
+ {
+ if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (id2.getParameters() == null)
+ {
+ if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return id1.getParameters().equals(id2.getParameters());
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return null;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ list.add(Integers.valueOf(genName.getTagNo()));
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getEncoded());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+ list.add(addrBytes);
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(list);
+ }
+ if (temp.size() == 0)
+ {
+ return null;
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/ocsp/OCSPUtil.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/ocsp/OCSPUtil.java
new file mode 100644
index 000000000..b134f1458
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/ocsp/OCSPUtil.java
@@ -0,0 +1,198 @@
+package org.spongycastle.ocsp;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.util.Strings;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+class OCSPUtil
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable oids = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+
+ oids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2WITHRSA");
+ oids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, "RIPEMD160WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, "RIPEMD128WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, "RIPEMD256WITHRSA");
+ oids.put(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ }
+
+ static DERObjectIdentifier getAlgorithmOID(
+ String algorithmName)
+ {
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (algorithms.containsKey(algorithmName))
+ {
+ return (DERObjectIdentifier)algorithms.get(algorithmName);
+ }
+
+ return new DERObjectIdentifier(algorithmName);
+ }
+
+ static String getAlgorithmName(
+ DERObjectIdentifier oid)
+ {
+ if (oids.containsKey(oid))
+ {
+ return (String)oids.get(oid);
+ }
+
+ return oid.getId();
+ }
+
+ static AlgorithmIdentifier getSigAlgID(
+ DERObjectIdentifier sigOid)
+ {
+ if (noParams.contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+ else
+ {
+ return new AlgorithmIdentifier(sigOid, new DERNull());
+ }
+ }
+
+ static Iterator getAlgNames()
+ {
+ Enumeration e = algorithms.keys();
+ List l = new ArrayList();
+
+ while (e.hasMoreElements())
+ {
+ l.add(e.nextElement());
+ }
+
+ return l.iterator();
+ }
+
+ static CertStore createCertStoreInstance(String type, CertStoreParameters params, String provider)
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return CertStore.getInstance(type, params);
+ }
+
+ return CertStore.getInstance(type, params, provider);
+ }
+
+ static MessageDigest createDigestInstance(String digestName, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return MessageDigest.getInstance(digestName);
+ }
+
+ return MessageDigest.getInstance(digestName, provider);
+ }
+
+ static Signature createSignatureInstance(String sigName, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return Signature.getInstance(sigName);
+ }
+
+ return Signature.getInstance(sigName, provider);
+ }
+
+ static CertificateFactory createX509CertificateFactory(String provider)
+ throws CertificateException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return CertificateFactory.getInstance("X.509");
+ }
+
+ return CertificateFactory.getInstance("X.509", provider);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateHolder.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateHolder.java
new file mode 100644
index 000000000..644883d4e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateHolder.java
@@ -0,0 +1,406 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.Holder;
+import org.spongycastle.asn1.x509.IssuerSerial;
+import org.spongycastle.asn1.x509.ObjectDigestInfo;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import java.security.cert.CertSelector;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+
+/**
+ * The Holder object.
+ *
+ * <pre>
+ * Holder ::= SEQUENCE {
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * -- the issuer and serial number of
+ * -- the holder's Public Key Certificate
+ * entityName [1] GeneralNames OPTIONAL,
+ * -- the name of the claimant or role
+ * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ * -- used to directly authenticate the holder,
+ * -- for example, an executable
+ * }
+ * </pre>
+ * @deprecated use org.spongycastle.cert.AttributeCertificateHolder
+ */
+public class AttributeCertificateHolder
+ implements CertSelector, Selector
+{
+ final Holder holder;
+
+ AttributeCertificateHolder(ASN1Sequence seq)
+ {
+ holder = Holder.getInstance(seq);
+ }
+
+ public AttributeCertificateHolder(X509Principal issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new org.spongycastle.asn1.x509.Holder(new IssuerSerial(
+ new GeneralNames(new GeneralName(issuerName)),
+ new ASN1Integer(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ X509Principal name;
+
+ try
+ {
+ name = PrincipalUtil.getIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+
+ holder = new Holder(new IssuerSerial(generateGeneralNames(name),
+ new ASN1Integer(cert.getSerialNumber())));
+ }
+
+ public AttributeCertificateHolder(X509Principal principal)
+ {
+ holder = new Holder(generateGeneralNames(principal));
+ }
+
+ /**
+ * Constructs a holder for v2 attribute certificates with a hash value for
+ * some type of object.
+ * <p>
+ * <code>digestedObjectType</code> can be one of the following:
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ * <p>
+ * This cannot be used if a v1 attribute certificate is used.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param otherObjectTypeID The object type ID if
+ * <code>digestedObjectType</code> is
+ * <code>otherObjectDigest</code>.
+ * @param objectDigest The hash value.
+ */
+ public AttributeCertificateHolder(int digestedObjectType,
+ String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)
+ {
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType,
+ new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(digestAlgorithm), Arrays
+ .clone(objectDigest)));
+ }
+
+ /**
+ * Returns the digest object type if an object digest info is used.
+ * <p>
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ *
+ * @return The digest object type or -1 if no object digest info is set.
+ */
+ public int getDigestedObjectType()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestedObjectType()
+ .getValue().intValue();
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the other object type ID if an object digest info is used.
+ *
+ * @return The other object type ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getDigestAlgorithm()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId()
+ .getId();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or <code>null</code> if no object digest info is set.
+ */
+ public byte[] getObjectDigest()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getObjectDigest().getBytes();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the digest algorithm ID if an object digest info is used.
+ *
+ * @return The digest algorithm ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getOtherObjectTypeID()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
+ }
+ return null;
+ }
+
+ private GeneralNames generateGeneralNames(X509Principal principal)
+ {
+ return new GeneralNames(new GeneralName(principal));
+ }
+
+ private boolean matchesDN(X509Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
+ .getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private Object[] getNames(GeneralName[] names)
+ {
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X509Principal(
+ ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ private Principal[] getPrincipals(GeneralNames names)
+ {
+ Object[] p = this.getNames(names.getNames());
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate holder
+ * entity names field.
+ *
+ * @return an array of Principal objects (usually X509Principal), null if no
+ * entity names field is set.
+ */
+ public Principal[] getEntityNames()
+ {
+ if (holder.getEntityName() != null)
+ {
+ return getPrincipals(holder.getEntityName());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the principals associated with the issuer attached to this holder
+ *
+ * @return an array of principals, null if no BaseCertificateID is set.
+ */
+ public Principal[] getIssuer()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return getPrincipals(holder.getBaseCertificateID().getIssuer());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the serial number associated with the issuer attached to this
+ * holder.
+ *
+ * @return the certificate serial number, null if no BaseCertificateID is
+ * set.
+ */
+ public BigInteger getSerialNumber()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue();
+ }
+
+ return null;
+ }
+
+ public Object clone()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)holder
+ .toASN1Object());
+ }
+
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
+ }
+
+ if (holder.getEntityName() != null)
+ {
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert),
+ holder.getEntityName()))
+ {
+ return true;
+ }
+ }
+ if (holder.getObjectDigestInfo() != null)
+ {
+ MessageDigest md = null;
+ try
+ {
+ md = MessageDigest.getInstance(getDigestAlgorithm(), "SC");
+
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ switch (getDigestedObjectType())
+ {
+ case ObjectDigestInfo.publicKey:
+ // TODO: DSA Dss-parms
+ md.update(cert.getPublicKey().getEncoded());
+ break;
+ case ObjectDigestInfo.publicKeyCert:
+ md.update(cert.getEncoded());
+ break;
+ }
+ if (!Arrays.areEqual(md.digest(), getObjectDigest()))
+ {
+ return false;
+ }
+ }
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+ return this.holder.equals(other.holder);
+ }
+
+ public int hashCode()
+ {
+ return this.holder.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateIssuer.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateIssuer.java
new file mode 100644
index 000000000..383292d78
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/AttributeCertificateIssuer.java
@@ -0,0 +1,212 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AttCertIssuer;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.V2Form;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.Selector;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Carrying class for an attribute certificate issuer.
+ */
+public class AttributeCertificateIssuer
+ implements CertSelector, Selector
+{
+ final ASN1Encodable form;
+
+ /**
+ * @param issuer
+ */
+ AttributeCertificateIssuer(
+ AttCertIssuer issuer)
+ {
+ form = issuer.getIssuer();
+ }
+
+ public AttributeCertificateIssuer(
+ X509Principal principal)
+ {
+ form = new V2Form(new GeneralNames(new GeneralName(principal)));
+ }
+
+ private Object[] getNames()
+ {
+ GeneralNames name;
+
+ if (form instanceof V2Form)
+ {
+ name = ((V2Form)form).getIssuerName();
+ }
+ else
+ {
+ name = (GeneralNames)form;
+ }
+
+ GeneralName[] names = name.getNames();
+
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X509Principal(((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate issuer object.
+ *
+ * @return an array of Principal objects (usually X509Principal)
+ */
+ public Principal[] getPrincipals()
+ {
+ Object[] p = this.getNames();
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ private boolean matchesDN(X509Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive().getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.cert.CertSelector#clone()
+ */
+ public Object clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.cert.CertSelector#match(java.security.cert.Certificate)
+ */
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (form instanceof V2Form)
+ {
+ V2Form issuer = (V2Form)form;
+ if (issuer.getBaseCertificateID() != null)
+ {
+ return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), issuer.getBaseCertificateID().getIssuer());
+ }
+
+ GeneralNames name = issuer.getIssuerName();
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), name))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ GeneralNames name = (GeneralNames)form;
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), name))
+ {
+ return true;
+ }
+ }
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateIssuer))
+ {
+ return false;
+ }
+
+ AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+ return this.form.equals(other.form);
+ }
+
+ public int hashCode()
+ {
+ return this.form.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509AttributeCertStoreSelector.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509AttributeCertStoreSelector.java
new file mode 100644
index 000000000..eafa21d0f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509AttributeCertStoreSelector.java
@@ -0,0 +1,488 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.Target;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.Targets;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Selector;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509CertSelector;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * This class is an <code>Selector</code> like implementation to select
+ * attribute certificates from a given set of criteria.
+ *
+ * @see org.spongycastle.x509.X509AttributeCertificate
+ * @see org.spongycastle.x509.X509Store
+ */
+public class X509AttributeCertStoreSelector
+ implements Selector
+{
+
+ // TODO: name constraints???
+
+ private AttributeCertificateHolder holder;
+
+ private AttributeCertificateIssuer issuer;
+
+ private BigInteger serialNumber;
+
+ private Date attributeCertificateValid;
+
+ private X509AttributeCertificate attributeCert;
+
+ private Collection targetNames = new HashSet();
+
+ private Collection targetGroups = new HashSet();
+
+ public X509AttributeCertStoreSelector()
+ {
+ super();
+ }
+
+ /**
+ * Decides if the given attribute certificate should be selected.
+ *
+ * @param obj The attribute certificate which should be checked.
+ * @return <code>true</code> if the attribute certificate can be selected,
+ * <code>false</code> otherwise.
+ */
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509AttributeCertificate))
+ {
+ return false;
+ }
+
+ X509AttributeCertificate attrCert = (X509AttributeCertificate) obj;
+
+ if (this.attributeCert != null)
+ {
+ if (!this.attributeCert.equals(attrCert))
+ {
+ return false;
+ }
+ }
+ if (serialNumber != null)
+ {
+ if (!attrCert.getSerialNumber().equals(serialNumber))
+ {
+ return false;
+ }
+ }
+ if (holder != null)
+ {
+ if (!attrCert.getHolder().equals(holder))
+ {
+ return false;
+ }
+ }
+ if (issuer != null)
+ {
+ if (!attrCert.getIssuer().equals(issuer))
+ {
+ return false;
+ }
+ }
+
+ if (attributeCertificateValid != null)
+ {
+ try
+ {
+ attrCert.checkValidity(attributeCertificateValid);
+ }
+ catch (CertificateExpiredException e)
+ {
+ return false;
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ return false;
+ }
+ }
+ if (!targetNames.isEmpty() || !targetGroups.isEmpty())
+ {
+
+ byte[] targetInfoExt = attrCert
+ .getExtensionValue(X509Extensions.TargetInformation.getId());
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation
+ .getInstance(new ASN1InputStream(
+ ((DEROctetString) DEROctetString
+ .fromByteArray(targetInfoExt)).getOctets())
+ .readObject());
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+ Targets[] targetss = targetinfo.getTargetsObjects();
+ if (!targetNames.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetNames.contains(targets[j]
+ .getTargetName()))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ if (!targetGroups.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetGroups.contains(targets[j]
+ .getTargetGroup()))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return the clone.
+ */
+ public Object clone()
+ {
+ X509AttributeCertStoreSelector sel = new X509AttributeCertStoreSelector();
+ sel.attributeCert = attributeCert;
+ sel.attributeCertificateValid = getAttributeCertificateValid();
+ sel.holder = holder;
+ sel.issuer = issuer;
+ sel.serialNumber = serialNumber;
+ sel.targetGroups = getTargetGroups();
+ sel.targetNames = getTargetNames();
+ return sel;
+ }
+
+ /**
+ * Returns the attribute certificate which must be matched.
+ *
+ * @return Returns the attribute certificate.
+ */
+ public X509AttributeCertificate getAttributeCert()
+ {
+ return attributeCert;
+ }
+
+ /**
+ * Set the attribute certificate to be matched. If <code>null</code> is
+ * given any will do.
+ *
+ * @param attributeCert The attribute certificate to set.
+ */
+ public void setAttributeCert(X509AttributeCertificate attributeCert)
+ {
+ this.attributeCert = attributeCert;
+ }
+
+ /**
+ * Get the criteria for the validity.
+ *
+ * @return Returns the attributeCertificateValid.
+ */
+ public Date getAttributeCertificateValid()
+ {
+ if (attributeCertificateValid != null)
+ {
+ return new Date(attributeCertificateValid.getTime());
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the time, when the certificate must be valid. If <code>null</code>
+ * is given any will do.
+ *
+ * @param attributeCertificateValid The attribute certificate validation
+ * time to set.
+ */
+ public void setAttributeCertificateValid(Date attributeCertificateValid)
+ {
+ if (attributeCertificateValid != null)
+ {
+ this.attributeCertificateValid = new Date(attributeCertificateValid
+ .getTime());
+ }
+ else
+ {
+ this.attributeCertificateValid = null;
+ }
+ }
+
+ /**
+ * Gets the holder.
+ *
+ * @return Returns the holder.
+ */
+ public AttributeCertificateHolder getHolder()
+ {
+ return holder;
+ }
+
+ /**
+ * Sets the holder. If <code>null</code> is given any will do.
+ *
+ * @param holder The holder to set.
+ */
+ public void setHolder(AttributeCertificateHolder holder)
+ {
+ this.holder = holder;
+ }
+
+ /**
+ * Returns the issuer criterion.
+ *
+ * @return Returns the issuer.
+ */
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return issuer;
+ }
+
+ /**
+ * Sets the issuer the attribute certificate must have. If <code>null</code>
+ * is given any will do.
+ *
+ * @param issuer The issuer to set.
+ */
+ public void setIssuer(AttributeCertificateIssuer issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ /**
+ * Gets the serial number the attribute certificate must have.
+ *
+ * @return Returns the serialNumber.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ /**
+ * Sets the serial number the attribute certificate must have. If
+ * <code>null</code> is given any will do.
+ *
+ * @param serialNumber The serialNumber to set.
+ */
+ public void setSerialNumber(BigInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name The name as a GeneralName (not <code>null</code>)
+ */
+ public void addTargetName(GeneralName name)
+ {
+ targetNames.add(name);
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void addTargetName(byte[] name) throws IOException
+ {
+ addTargetName(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target names criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of either GeneralName objects or byte[] arrays representing
+ * DER encoded GeneralName structures.
+ *
+ * @param names A collection of target names.
+ * @throws IOException if a parsing error occurs.
+ * @see #addTargetName(byte[])
+ * @see #addTargetName(GeneralName)
+ */
+ public void setTargetNames(Collection names) throws IOException
+ {
+ targetNames = extractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target names. The collection consists of <code>List</code>s
+ * made up of an <code>Integer</code> in the first entry and a DER encoded
+ * byte array or a <code>String</code> in the second entry.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ * @see #setTargetNames(Collection)
+ */
+ public Collection getTargetNames()
+ {
+ return Collections.unmodifiableCollection(targetNames);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param group The group as GeneralName form (not <code>null</code>)
+ */
+ public void addTargetGroup(GeneralName group)
+ {
+ targetGroups.add(group);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void addTargetGroup(byte[] name) throws IOException
+ {
+ addTargetGroup(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target groups criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER
+ * encoded GeneralNames.
+ *
+ * @param names A collection of target groups.
+ * @throws IOException if a parsing error occurs.
+ * @see #addTargetGroup(byte[])
+ * @see #addTargetGroup(GeneralName)
+ */
+ public void setTargetGroups(Collection names) throws IOException
+ {
+ targetGroups = extractGeneralNames(names);
+ }
+
+
+
+ /**
+ * Gets the target groups. The collection consists of <code>List</code>s
+ * made up of an <code>Integer</code> in the first entry and a DER encoded
+ * byte array or a <code>String</code> in the second entry.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ * @see #setTargetGroups(Collection)
+ */
+ public Collection getTargetGroups()
+ {
+ return Collections.unmodifiableCollection(targetGroups);
+ }
+
+ private Set extractGeneralNames(Collection names)
+ throws IOException
+ {
+ if (names == null || names.isEmpty())
+ {
+ return new HashSet();
+ }
+ Set temp = new HashSet();
+ for (Iterator it = names.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+ if (o instanceof GeneralName)
+ {
+ temp.add(o);
+ }
+ else
+ {
+ temp.add(GeneralName.getInstance(ASN1Primitive.fromByteArray((byte[])o)));
+ }
+ }
+ return temp;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509CRLStoreSelector.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509CRLStoreSelector.java
new file mode 100644
index 000000000..a6c8cc31f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509CRLStoreSelector.java
@@ -0,0 +1,26 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.security.cert.X509CRLSelector;
+import java.security.cert.CRL;
+
+public class X509CRLStoreSelector
+ extends X509CRLSelector
+ implements Selector
+{
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof CRL))
+ {
+ return false;
+ }
+
+ return super.match((CRL)obj);
+ }
+
+ public boolean match(CRL obj)
+ {
+ return this.match((Object)obj);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509CertStoreSelector.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509CertStoreSelector.java
new file mode 100644
index 000000000..2c0e6cc34
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509CertStoreSelector.java
@@ -0,0 +1,26 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.security.cert.X509CertSelector;
+import java.security.cert.Certificate;
+
+public class X509CertStoreSelector
+ extends X509CertSelector
+ implements Selector
+{
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof Certificate))
+ {
+ return false;
+ }
+
+ return super.match((Certificate)obj);
+ }
+
+ public boolean match(Certificate obj)
+ {
+ return this.match((Object)obj);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509Util.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509Util.java
new file mode 100644
index 000000000..b61fd157f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509Util.java
@@ -0,0 +1,397 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.Strings;
+
+class X509Util
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull());
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull());
+ params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull());
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, new DERNull());
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, new DERNull());
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ static DERObjectIdentifier getAlgorithmOID(
+ String algorithmName)
+ {
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (algorithms.containsKey(algorithmName))
+ {
+ return (DERObjectIdentifier)algorithms.get(algorithmName);
+ }
+
+ return new DERObjectIdentifier(algorithmName);
+ }
+
+ static AlgorithmIdentifier getSigAlgID(
+ DERObjectIdentifier sigOid,
+ String algorithmName)
+ {
+ if (noParams.contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (params.containsKey(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ return new AlgorithmIdentifier(sigOid, new DERNull());
+ }
+ }
+
+ static Iterator getAlgNames()
+ {
+ Enumeration e = algorithms.keys();
+ List l = new ArrayList();
+
+ while (e.hasMoreElements())
+ {
+ l.add(e.nextElement());
+ }
+
+ return l.iterator();
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm);
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm,
+ String provider)
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ if (provider != null)
+ {
+ return Signature.getInstance(algorithm, provider);
+ }
+ else
+ {
+ return Signature.getInstance(algorithm);
+ }
+ }
+
+ static byte[] calculateSignature(
+ DERObjectIdentifier sigOid,
+ String sigName,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName);
+
+ if (random != null)
+ {
+ sig.initSign(key);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static byte[] calculateSignature(
+ DERObjectIdentifier sigOid,
+ String sigName,
+ String provider,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName, provider);
+
+ if (random != null)
+ {
+ sig.initSign(key);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static class Implementation
+ {
+ Object engine;
+ Provider provider;
+
+ Implementation(
+ Object engine,
+ Provider provider)
+ {
+ this.engine = engine;
+ this.provider = provider;
+ }
+
+ Object getEngine()
+ {
+ return engine;
+ }
+
+ Provider getProvider()
+ {
+ return provider;
+ }
+ }
+
+ /**
+ * see if we can find an algorithm (or its alias and what it represents) in
+ * the property table for the given provider.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm,
+ Provider prov)
+ throws NoSuchAlgorithmException
+ {
+ algorithm = Strings.toUpperCase(algorithm);
+
+ String alias;
+
+ while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null)
+ {
+ algorithm = alias;
+ }
+
+ String className = prov.getProperty(baseName + "." + algorithm);
+
+ if (className != null)
+ {
+ try
+ {
+ Class cls;
+ ClassLoader clsLoader = prov.getClass().getClassLoader();
+
+ if (clsLoader != null)
+ {
+ cls = clsLoader.loadClass(className);
+ }
+ else
+ {
+ cls = Class.forName(className);
+ }
+
+ return new Implementation(cls.newInstance(), prov);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!");
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!");
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm + " for provider " + prov.getName());
+ }
+
+ /**
+ * return an implementation for a given algorithm/provider.
+ * If the provider is null, we grab the first avalaible who has the required algorithm.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ Provider[] prov = Security.getProviders();
+
+ //
+ // search every provider looking for the algorithm we want.
+ //
+ for (int i = 0; i != prov.length; i++)
+ {
+ //
+ // try case insensitive
+ //
+ Implementation imp = getImplementation(baseName, Strings.toUpperCase(algorithm), prov[i]);
+ if (imp != null)
+ {
+ return imp;
+ }
+
+ try
+ {
+ imp = getImplementation(baseName, algorithm, prov[i]);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // continue
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm);
+ }
+
+ static Provider getProvider(String provider)
+ throws NoSuchProviderException
+ {
+ Provider prov = Security.getProvider(provider);
+
+ if (prov == null)
+ {
+ throw new NoSuchProviderException("Provider " + provider + " not found");
+ }
+
+ return prov;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V1CertificateGenerator.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V1CertificateGenerator.java
new file mode 100644
index 000000000..58302d731
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V1CertificateGenerator.java
@@ -0,0 +1,345 @@
+package org.spongycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ * @deprecated use org.spongycastle.cert.X509v1CertificateBuilder.
+ */
+public class X509V1CertificateGenerator
+{
+ private V1TBSCertificateGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+
+ public X509V1CertificateGenerator()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.valueOf(0)) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+ new ByteArrayInputStream(key.getEncoded())).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC" and the passed in source of randomness
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider and the passed in source of randomness
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateEncodingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ try
+ {
+ return new X509CertificateObject(Certificate.getInstance((new DERSequence(v))));
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java
new file mode 100644
index 000000000..2b1bc6bf7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2AttributeCertificateGenerator.java
@@ -0,0 +1,281 @@
+package org.spongycastle.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AttCertIssuer;
+import org.spongycastle.asn1.x509.Attribute;
+import org.spongycastle.asn1.x509.AttributeCertificate;
+import org.spongycastle.asn1.x509.V2AttributeCertificateInfoGenerator;
+import org.spongycastle.asn1.x509.AttributeCertificateInfo;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Strings;
+
+/**
+ * class to produce an X.509 Version 2 AttributeCertificate.
+ */
+public class X509V2AttributeCertificateGenerator
+{
+ private V2AttributeCertificateInfoGenerator acInfoGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private Hashtable extensions = null;
+ private Vector extOrdering = null;
+ private static Hashtable algorithms = new Hashtable();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+ algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+ algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.put("SHA1WITHECDSA", new DERObjectIdentifier("1.2.840.10045.4.1"));
+ algorithms.put("ECDSAWITHSHA1", new DERObjectIdentifier("1.2.840.10045.4.1"));
+ }
+
+ public X509V2AttributeCertificateGenerator()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ extensions = null;
+ extOrdering = null;
+ }
+
+ /**
+ * Set the Holder of this Attribute Certificate
+ */
+ public void setHolder(
+ AttributeCertificateHolder holder)
+ {
+ acInfoGen.setHolder(holder.holder);
+ }
+
+ /**
+ * Set the issuer
+ */
+ public void setIssuer(
+ AttributeCertificateIssuer issuer)
+ {
+ acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form));
+ }
+
+ /**
+ * Set the Signature inside the AttributeCertificateInfo
+ */
+ public void setSignature(
+ AlgorithmIdentifier sig)
+ {
+ acInfoGen.setSignature(sig);
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ acInfoGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ acInfoGen.setStartDate(new ASN1GeneralizedTime(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ acInfoGen.setEndDate(new ASN1GeneralizedTime(date));
+ }
+
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ sigOID = (DERObjectIdentifier)algorithms.get(Strings.toUpperCase(signatureAlgorithm));
+
+ if (sigOID == null)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = new AlgorithmIdentifier(this.sigOID, new DERNull());
+
+ acInfoGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * add an attribute
+ */
+ public void addAttribute(
+ X509Attribute attribute)
+ {
+ acInfoGen.addAttribute(Attribute.getInstance(attribute.toASN1Object()));
+ }
+
+ public void setIssuerUniqueId(
+ boolean[] iui)
+ {
+ // [TODO] convert boolean array to bit string
+ //acInfoGen.setIssuerUniqueID(iui);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * @throws IOException
+ */
+ public void addExtension(
+ String OID,
+ boolean critical,
+ ASN1Encodable value)
+ throws IOException
+ {
+ this.addExtension(OID, critical, value.toASN1Primitive().getEncoded());
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public void addExtension(
+ String OID,
+ boolean critical,
+ byte[] value)
+ {
+ if (extensions == null)
+ {
+ extensions = new Hashtable();
+ extOrdering = new Vector();
+ }
+
+ DERObjectIdentifier oid = new DERObjectIdentifier(OID);
+
+ extensions.put(oid, new X509Extension(critical, new DEROctetString(value)));
+ extOrdering.addElement(oid);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509AttributeCertificate generateCertificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateCertificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ */
+ public X509AttributeCertificate generateCertificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ Signature sig = null;
+
+ if (sigOID == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ try
+ {
+ sig = Signature.getInstance(sigOID.getId(), provider);
+ }
+ catch (NoSuchAlgorithmException ex)
+ {
+ try
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new SecurityException("exception creating signature: " + e.toString());
+ }
+ }
+
+ sig.initSign(key);
+
+ if (extensions != null)
+ {
+ acInfoGen.setExtensions(new X509Extensions(extOrdering, extensions));
+ }
+
+ AttributeCertificateInfo acInfo = acInfoGen.generateAttributeCertificateInfo();
+
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(acInfo);
+
+ sig.update(bOut.toByteArray());
+ }
+ catch (Exception e)
+ {
+ throw new SecurityException("exception encoding Attribute cert - " + e);
+ }
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(acInfo);
+ v.add(sigAlgId);
+ v.add(new DERBitString(sig.sign()));
+
+ try
+ {
+ return new X509V2AttributeCertificate(new AttributeCertificate(new DERSequence(v)));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("constructed invalid certificate!");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2CRLGenerator.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2CRLGenerator.java
new file mode 100644
index 000000000..419f9706f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V2CRLGenerator.java
@@ -0,0 +1,435 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V2TBSCertListGenerator;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.provider.X509CRLObject;
+
+/**
+ * class to produce an X.509 Version 2 CRL.
+ * @deprecated use org.spongycastle.cert.X509v2CRLBuilder.
+ */
+public class X509V2CRLGenerator
+{
+ private V2TBSCertListGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V2CRLGenerator()
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setThisUpdate(
+ Date date)
+ {
+ tbsGen.setThisUpdate(new Time(date));
+ }
+
+ public void setNextUpdate(
+ Date date)
+ {
+ tbsGen.setNextUpdate(new Time(date));
+ }
+
+ /**
+ * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise
+ * or 0 if CRLReason is not to be used
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason);
+ }
+
+ /**
+ * Add a CRL entry with an Invalidity Date extension as well as a CRLReason extension.
+ * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise
+ * or 0 if CRLReason is not to be used
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason, Date invalidityDate)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason, new ASN1GeneralizedTime(invalidityDate));
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, X509Extensions extensions)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), Extensions.getInstance(extensions));
+ }
+
+ /**
+ * Add the CRLEntry objects contained in a previous CRL.
+ *
+ * @param other the X509CRL to source the other entries from.
+ */
+ public void addCRL(X509CRL other)
+ throws CRLException
+ {
+ Set revocations = other.getRevokedCertificates();
+
+ if (revocations != null)
+ {
+ Iterator it = revocations.iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntry entry = (X509CRLEntry)it.next();
+
+ ASN1InputStream aIn = new ASN1InputStream(entry.getEncoded());
+
+ try
+ {
+ tbsGen.addCRLEntry(ASN1Sequence.getInstance(aIn.readObject()));
+ }
+ catch (IOException e)
+ {
+ throw new CRLException("exception processing encoding of CRL: " + e.toString());
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509CRL(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider "SC" and an user defined SecureRandom object as
+ * source of randomness.
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509CRL(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509CRL(key, provider, null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509CRL generate(
+ PrivateKey key)
+ throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider and an user defined SecureRandom object as
+ * source of randomness.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertList tbsCrl = generateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCRLException("cannot generate CRL encoding", e);
+ }
+
+ return generateJcaObject(tbsCrl, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the passed in provider for the signing.
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ String provider)
+ throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertList tbsCrl = generateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCRLException("cannot generate CRL encoding", e);
+ }
+
+ return generateJcaObject(tbsCrl, signature);
+ }
+
+ private TBSCertList generateCertList()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertList();
+ }
+
+ private X509CRL generateJcaObject(TBSCertList tbsCrl, byte[] signature)
+ throws CRLException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCrl);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CRLObject(new CertificateList(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+
+ private static class ExtCRLException
+ extends CRLException
+ {
+ Throwable cause;
+
+ ExtCRLException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V3CertificateGenerator.java b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V3CertificateGenerator.java
new file mode 100644
index 000000000..2ee754ad6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.1/org/spongycastle/x509/X509V3CertificateGenerator.java
@@ -0,0 +1,495 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V3TBSCertificateGenerator;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.provider.X509CertificateObject;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ * @deprecated use org.spongycastle.cert.X509v3CertificateBuilder.
+ */
+public class X509V3CertificateGenerator
+{
+ private V3TBSCertificateGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V3CertificateGenerator()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.valueOf(0)) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo.getInstance(new ASN1InputStream(key.getEncoded()).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * Set the subject unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setSubjectUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setSubjectUniqueID(booleanToBitString(uniqueID));
+ }
+
+ /**
+ * Set the issuer unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setIssuerUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setIssuerUniqueID(booleanToBitString(uniqueID));
+ }
+
+ private DERBitString booleanToBitString(boolean[] id)
+ {
+ byte[] bytes = new byte[(id.length + 7) / 8];
+
+ for (int i = 0; i != id.length; i++)
+ {
+ bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0;
+ }
+
+ int pad = id.length % 8;
+
+ if (pad == 0)
+ {
+ return new DERBitString(bytes);
+ }
+ else
+ {
+ return new DERBitString(bytes, 8 - pad);
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ String oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extValue = cert.getExtensionValue(oid);
+
+ if (extValue == null)
+ {
+ throw new CertificateParsingException("extension " + oid + " not present");
+ }
+
+ try
+ {
+ ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue);
+
+ this.addExtension(oid, critical, value);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateParsingException(e.toString());
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ this.copyAndAddExtension(oid.getId(), critical, cert);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC", and the passed in source of randomness
+ * (if required).
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider, and the passed in source of randomness
+ * (if required).
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private TBSCertificate generateTbsCert()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertificate();
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateParsingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.2/org/spongycastle/jce/exception/ExtCertPathBuilderException.java b/libraries/spongycastle/prov/src/main/jdk1.2/org/spongycastle/jce/exception/ExtCertPathBuilderException.java
new file mode 100644
index 000000000..b238580f7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.2/org/spongycastle/jce/exception/ExtCertPathBuilderException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.jce.exception;
+
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathBuilderException;
+
+public class ExtCertPathBuilderException
+ extends CertPathBuilderException
+ implements ExtException
+{
+ private Throwable cause;
+
+ public ExtCertPathBuilderException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathBuilderException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.2/org/spongycastle/jce/exception/ExtCertPathValidatorException.java b/libraries/spongycastle/prov/src/main/jdk1.2/org/spongycastle/jce/exception/ExtCertPathValidatorException.java
new file mode 100644
index 000000000..bd6e42d09
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.2/org/spongycastle/jce/exception/ExtCertPathValidatorException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.jce.exception;
+
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+
+public class ExtCertPathValidatorException
+ extends CertPathValidatorException
+ implements ExtException
+{
+ private Throwable cause;
+
+ public ExtCertPathValidatorException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathValidatorException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause, certPath, index);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/ProviderJcaJceHelper.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/ProviderJcaJceHelper.java
new file mode 100644
index 000000000..02580c0d4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/ProviderJcaJceHelper.java
@@ -0,0 +1,104 @@
+package org.spongycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+public class ProviderJcaJceHelper
+ implements JcaJceHelper
+{
+ protected final Provider provider;
+
+ public ProviderJcaJceHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ public Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException
+ {
+ return Cipher.getInstance(algorithm, provider.getName());
+ }
+
+ public Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Mac.getInstance(algorithm, provider.getName());
+ }
+
+ public KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyAgreement.getInstance(algorithm, provider.getName());
+ }
+
+ public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return AlgorithmParameterGenerator.getInstance(algorithm, provider.getName());
+ }
+
+ public AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return AlgorithmParameters.getInstance(algorithm, provider.getName());
+ }
+
+ public KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyGenerator.getInstance(algorithm, provider.getName());
+ }
+
+ public KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyFactory.getInstance(algorithm, provider.getName());
+ }
+
+ public SecretKeyFactory createSecretKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return SecretKeyFactory.getInstance(algorithm, provider.getName());
+ }
+
+ public KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyPairGenerator.getInstance(algorithm, provider.getName());
+ }
+
+ public MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return MessageDigest.getInstance(algorithm, provider.getName());
+ }
+
+ public Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Signature.getInstance(algorithm, provider.getName());
+ }
+
+ public CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException
+ {
+ return CertificateFactory.getInstance(algorithm, provider.getName());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 000000000..390708bc6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,201 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+
+public abstract class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class OAEP
+ extends AlgorithmParametersSpi
+ {
+ AlgorithmParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
+ */
+ protected byte[] engineGetEncoded()
+ {
+ return null;
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ this.currentSpec = paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+
+ throw new IOException("Operation not supported");
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "OAEP Parameters";
+ }
+ }
+
+ public static class PSS
+ extends AlgorithmParametersSpi
+ {
+ /**
+ * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+ */
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ RSASSAPSSparams pssP = new RSASSAPSSparams(RSASSAPSSparams.DEFAULT_HASH_ALGORITHM, RSASSAPSSparams.DEFAULT_MASK_GEN_FUNCTION, new ASN1Integer(20), RSASSAPSSparams.DEFAULT_TRAILER_FIELD);
+
+ dOut.writeObject(pssP);
+ dOut.close();
+
+ return bOut.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ throw new InvalidParameterSpecException("Not implemented");
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "PSS Parameters";
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
new file mode 100644
index 000000000..be4083e3c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
@@ -0,0 +1,428 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+
+public class PSSSignatureSpi
+ extends Signature
+{
+ private AlgorithmParameters engineParams;
+ private AsymmetricBlockCipher signer;
+ private Digest contentDigest;
+ private Digest mgfDigest;
+ private int saltLength;
+ private byte trailer;
+ private boolean isRaw;
+ private ByteArrayOutputStream bOut;
+ private org.spongycastle.crypto.signers.PSSSigner pss;
+ private CipherParameters sigParams;
+
+ private byte getTrailer(
+ int trailerField)
+ {
+ if (trailerField == 1)
+ {
+ return org.spongycastle.crypto.signers.PSSSigner.TRAILER_IMPLICIT;
+ }
+
+ throw new IllegalArgumentException("unknown trailer field");
+ }
+
+ private void setupContentDigest()
+ {
+ if (isRaw)
+ {
+ this.contentDigest = new NullPssDigest(mgfDigest);
+ }
+ else
+ {
+ this.contentDigest = mgfDigest;
+ }
+ }
+
+ protected PSSSignatureSpi(
+ String name,
+ AsymmetricBlockCipher signer,
+ Digest digest)
+ {
+ super(name);
+
+ this.signer = signer;
+ this.mgfDigest = digest;
+
+ if (digest != null)
+ {
+ this.saltLength = digest.getDigestSize();
+ }
+ else
+ {
+ this.saltLength = 20;
+ }
+
+ this.isRaw = false;
+
+ setupContentDigest();
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected PSSSignatureSpi(
+ String name,
+ AsymmetricBlockCipher signer,
+ Digest digest,
+ boolean isRaw)
+ {
+ super(name);
+
+ this.signer = signer;
+ this.mgfDigest = digest;
+
+ if (digest != null)
+ {
+ this.saltLength = digest.getDigestSize();
+ }
+ else
+ {
+ this.saltLength = 20;
+ }
+
+ this.isRaw = isRaw;
+
+ setupContentDigest();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPublicKey instance");
+ }
+
+ sigParams = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ if (isRaw)
+ {
+ bOut = new ByteArrayOutputStream();
+ }
+ else
+ {
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(false,
+ sigParams);
+ }
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ sigParams = new ParametersWithRandom(RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey), random);
+
+ if (isRaw)
+ {
+ bOut = new ByteArrayOutputStream();
+ }
+ else
+ {
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(true, sigParams);
+ }
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ sigParams = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ if (isRaw)
+ {
+ bOut = new ByteArrayOutputStream();
+ }
+ else
+ {
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(true, sigParams);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ if (isRaw)
+ {
+ bOut.write(b);
+ }
+ else
+ {
+ pss.update(b);
+ }
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ if (isRaw)
+ {
+ bOut.write(b, off, len);
+ }
+ else
+ {
+ pss.update(b, off, len);
+ }
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ if (isRaw)
+ {
+ byte[] hash = bOut.toByteArray();
+ contentDigest = mgfDigest = guessDigest(hash.length);
+ saltLength = contentDigest.getDigestSize();
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, new NullPssDigest(contentDigest), mgfDigest, saltLength);
+
+ pss.init(true, sigParams);
+ }
+ return pss.generateSignature();
+ }
+ catch (CryptoException e)
+ {
+ throw new SignatureException(e.getMessage());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ if (isRaw)
+ {
+ byte[] hash = bOut.toByteArray();
+ contentDigest = mgfDigest = guessDigest(hash.length);
+ saltLength = contentDigest.getDigestSize();
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, new NullPssDigest(contentDigest), mgfDigest, saltLength);
+
+ pss.init(false, sigParams);
+
+ pss.update(hash, 0, hash.length);
+ }
+ return pss.verifySignature(sigBytes);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ throws InvalidParameterException
+ {
+ throw new InvalidParameterException("Only PSSParameterSpec supported");
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return engineParams;
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineGetParameter unsupported");
+ }
+
+ private Digest guessDigest(int size)
+ {
+ switch (size)
+ {
+ case 20:
+ return new SHA1Digest();
+ case 28:
+ return new SHA224Digest();
+ case 32:
+ return new SHA256Digest();
+ case 48:
+ return new SHA384Digest();
+ case 64:
+ return new SHA512Digest();
+ }
+
+ return null;
+ }
+
+ static public class nonePSS
+ extends PSSSignatureSpi
+ {
+ public nonePSS()
+ {
+ super("NONEwithRSAandMGF1", new RSABlindedEngine(), null, true);
+ }
+ }
+
+ static public class PSSwithRSA
+ extends PSSSignatureSpi
+ {
+ public PSSwithRSA()
+ {
+ super("SHA1withRSAandMGF1", new RSABlindedEngine(), null);
+ }
+ }
+
+ static public class SHA1withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA1withRSA()
+ {
+ super("SHA1withRSAandMGF1", new RSABlindedEngine(), new SHA1Digest());
+ }
+ }
+
+ static public class SHA224withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA224withRSA()
+ {
+ super("SHA224withRSAandMGF1", new RSABlindedEngine(), new SHA224Digest());
+ }
+ }
+
+ static public class SHA256withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA256withRSA()
+ {
+ super("SHA256withRSAandMGF1", new RSABlindedEngine(), new SHA256Digest());
+ }
+ }
+
+ static public class SHA384withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA384withRSA()
+ {
+ super("SHA384withRSAandMGF1", new RSABlindedEngine(), new SHA384Digest());
+ }
+ }
+
+ static public class SHA512withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA512withRSA()
+ {
+ super("SHA512withRSAandMGF1", new RSABlindedEngine(), new SHA512Digest());
+ }
+ }
+
+ private class NullPssDigest
+ implements Digest
+ {
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ private Digest baseDigest;
+ private boolean oddTime = true;
+
+ public NullPssDigest(Digest mgfDigest)
+ {
+ this.baseDigest = mgfDigest;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "NULL";
+ }
+
+ public int getDigestSize()
+ {
+ return baseDigest.getDigestSize();
+ }
+
+ public void update(byte in)
+ {
+ bOut.write(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ bOut.write(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ byte[] res = bOut.toByteArray();
+
+ if (oddTime)
+ {
+ System.arraycopy(res, 0, out, outOff, res.length);
+ }
+ else
+ {
+ baseDigest.update(res, 0, res.length);
+
+ baseDigest.doFinal(out, outOff);
+ }
+
+ reset();
+
+ oddTime = !oddTime;
+
+ return res.length;
+ }
+
+ public void reset()
+ {
+ bOut.reset();
+ baseDigest.reset();
+ }
+
+ public int getByteLength()
+ {
+ return 0;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
new file mode 100644
index 000000000..467893f37
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
@@ -0,0 +1,397 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import org.spongycastle.jce.cert.CertPath;
+import java.security.cert.CertificateException;
+import org.spongycastle.jce.cert.CertificateFactorySpi;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.jce.provider.X509CRLObject;
+import org.spongycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class for dealing with X509 certificates.
+ * <p>
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+public class CertificateFactory
+ extends CertificateFactorySpi
+{
+ private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
+ private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
+
+ private ASN1Set sData = null;
+ private int sDataObjectCount = 0;
+ private InputStream currentStream = null;
+
+ private ASN1Set sCrlData = null;
+ private int sCrlDataObjectCount = 0;
+ private InputStream currentCrlStream = null;
+
+ private java.security.cert.Certificate readDERCertificate(
+ ASN1InputStream dIn)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+
+ return getCertificate();
+ }
+ }
+
+ return new X509CertificateObject(
+ Certificate.getInstance(seq));
+ }
+
+ private java.security.cert.Certificate getCertificate()
+ throws CertificateParsingException
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.size())
+ {
+ Object obj = sData.getObjectAt(sDataObjectCount++);
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new X509CertificateObject(
+ Certificate.getInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private java.security.cert.Certificate readPEMCertificate(
+ InputStream in)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return new X509CertificateObject(
+ Certificate.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ protected CRL createCRL(CertificateList c)
+ throws CRLException
+ {
+ return new X509CRLObject(c);
+ }
+
+ private CRL readPEMCRL(
+ InputStream in)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ private CRL readDERCRL(
+ ASN1InputStream aIn)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = (ASN1Sequence)aIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sCrlData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
+
+ return getCRL();
+ }
+ }
+
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ private CRL getCRL()
+ throws CRLException
+ {
+ if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size())
+ {
+ return null;
+ }
+
+ return createCRL(
+ CertificateList.getInstance(
+ sCrlData.getObjectAt(sCrlDataObjectCount++)));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public java.security.cert.Certificate engineGenerateCertificate(
+ InputStream in)
+ throws CertificateException
+ {
+ if (currentStream == null)
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != in) // reset if input stream has changed
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.size())
+ {
+ return getCertificate();
+ }
+ else
+ {
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(in);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCertificate(pis);
+ }
+ else
+ {
+ return readDERCertificate(new ASN1InputStream(pis));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExCertificateException(e);
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public Collection engineGenerateCertificates(
+ InputStream inStream)
+ throws CertificateException
+ {
+ java.security.cert.Certificate cert;
+ List certs = new ArrayList();
+
+ while ((cert = engineGenerateCertificate(inStream)) != null)
+ {
+ certs.add(cert);
+ }
+
+ return certs;
+ }
+
+ /**
+ * Generates a certificate revocation list (CRL) object and initializes
+ * it with the data read from the input stream inStream.
+ */
+ public CRL engineGenerateCRL(
+ InputStream inStream)
+ throws CRLException
+ {
+ if (currentCrlStream == null)
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+ else if (currentCrlStream != inStream) // reset if input stream has changed
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sCrlData != null)
+ {
+ if (sCrlDataObjectCount != sCrlData.size())
+ {
+ return getCRL();
+ }
+ else
+ {
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(inStream);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCRL(pis);
+ }
+ else
+ { // lazy evaluate to help processing of large CRLs
+ return readDERCRL(new ASN1InputStream(pis, true));
+ }
+ }
+ catch (CRLException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the CRLs read from
+ * the given input stream inStream.
+ *
+ * The inStream may contain a sequence of DER-encoded CRLs, or
+ * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
+ * only signficant field being crls. In particular the signature
+ * and the contents are ignored.
+ */
+ public Collection engineGenerateCRLs(
+ InputStream inStream)
+ throws CRLException
+ {
+ CRL crl;
+ List crls = new ArrayList();
+
+ while ((crl = engineGenerateCRL(inStream)) != null)
+ {
+ crls.add(crl);
+ }
+
+ return crls;
+ }
+
+ public Iterator engineGetCertPathEncodings()
+ {
+ return null; // TODO: PKIXCertPath.certPathEncodings.iterator();
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream)
+ throws CertificateException
+ {
+ return engineGenerateCertPath(inStream, "PkiPath");
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ return new PKIXCertPath(inStream, encoding);
+ }
+
+ public CertPath engineGenerateCertPath(
+ List certificates)
+ throws CertificateException
+ {
+ Iterator iter = certificates.iterator();
+ Object obj;
+ while (iter.hasNext())
+ {
+ obj = iter.next();
+ if (obj != null)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ throw new CertificateException("list contains non X509Certificate object while creating CertPath\n" + obj.toString());
+ }
+ }
+ }
+ return new PKIXCertPath(certificates);
+ }
+
+ private class ExCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public ExCertificateException(Throwable cause)
+ {
+ this.cause = cause;
+ }
+
+ public ExCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
new file mode 100644
index 000000000..0bc938326
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
@@ -0,0 +1,379 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.security.NoSuchProviderException;
+import org.spongycastle.jce.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.io.pem.PemObject;
+import org.spongycastle.util.io.pem.PemWriter;
+
+/**
+ * CertPath implementation for X.509 certificates.
+ * <br />
+ **/
+public class PKIXCertPath
+ extends CertPath
+{
+ static final List certPathEncodings;
+
+ static
+ {
+ List encodings = new ArrayList();
+ encodings.add("PkiPath");
+ encodings.add("PEM");
+ encodings.add("PKCS7");
+ certPathEncodings = Collections.unmodifiableList(encodings);
+ }
+
+ private List certificates;
+
+ /**
+ * @param certs
+ */
+ private List sortCerts(
+ List certs)
+ {
+ try
+ {
+ if (certs.size() < 2)
+ {
+ return certs;
+ }
+
+ X509Principal issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)certs.get(0)));
+ boolean okay = true;
+
+ for (int i = 1; i != certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+
+ if (issuer.equals(PrincipalUtil.getSubjectX509Principal(cert)))
+ {
+ issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)certs.get(i)));
+ }
+ else
+ {
+ okay = false;
+ break;
+ }
+ }
+
+ if (okay)
+ {
+ return certs;
+ }
+
+ // find end-entity cert
+ List retList = new ArrayList(certs.size());
+ List orig = new ArrayList(certs);
+
+ for (int i = 0; i < certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+ boolean found = false;
+
+ X509Principal subject = PrincipalUtil.getSubjectX509Principal(cert);
+
+ for (int j = 0; j != certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (PrincipalUtil.getIssuerX509Principal(c).equals(subject))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ retList.add(cert);
+ certs.remove(i);
+ }
+ }
+
+ // can only have one end entity cert - something's wrong, give up.
+ if (retList.size() > 1)
+ {
+ return orig;
+ }
+
+ for (int i = 0; i != retList.size(); i++)
+ {
+ issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)retList.get(i)));
+
+ for (int j = 0; j < certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (issuer.equals(PrincipalUtil.getSubjectX509Principal(c)))
+ {
+ retList.add(c);
+ certs.remove(j);
+ break;
+ }
+ }
+ }
+
+ // make sure all certificates are accounted for.
+ if (certs.size() > 0)
+ {
+ return orig;
+ }
+
+ return retList;
+ }
+ catch (Exception e)
+ {
+ return certs;
+ }
+ }
+
+ PKIXCertPath(List certificates)
+ {
+ super("X.509");
+ this.certificates = sortCerts(new ArrayList(certificates));
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ **/
+ PKIXCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ super("X.509");
+ try
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Primitive derObject = derInStream.readObject();
+ if (!(derObject instanceof ASN1Sequence))
+ {
+ throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+ }
+ Enumeration e = ((ASN1Sequence)derObject).getObjects();
+ certificates = new ArrayList();
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ while (e.hasMoreElements())
+ {
+ ASN1Encodable element = (ASN1Encodable)e.nextElement();
+ byte[] encoded = element.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ certificates.add(0, certFactory.generateCertificate(
+ new ByteArrayInputStream(encoded)));
+ }
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7") || encoding.equalsIgnoreCase("PEM"))
+ {
+ inStream = new BufferedInputStream(inStream);
+ certificates = new ArrayList();
+ CertificateFactory certFactory= CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ Certificate cert;
+ while ((cert = certFactory.generateCertificate(inStream)) != null)
+ {
+ certificates.add(cert);
+ }
+ }
+ else
+ {
+ throw new CertificateException("unsupported encoding: " + encoding);
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString());
+ }
+ catch (NoSuchProviderException ex)
+ {
+ throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString());
+ }
+
+ this.certificates = sortCerts(certificates);
+ }
+
+ /**
+ * Returns an iteration of the encodings supported by this
+ * certification path, with the default encoding
+ * first. Attempts to modify the returned Iterator via its
+ * remove method result in an UnsupportedOperationException.
+ *
+ * @return an Iterator over the names of the supported encodings (as Strings)
+ **/
+ public Iterator getEncodings()
+ {
+ return certPathEncodings.iterator();
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the default encoding.
+ *
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error occurs
+ **/
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ Iterator iter = getEncodings();
+ if (iter.hasNext())
+ {
+ Object enc = iter.next();
+ if (enc instanceof String)
+ {
+ return getEncoded((String)enc);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the specified encoding.
+ *
+ * @param encoding the name of the encoding to use
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error
+ * occurs or the encoding requested is not supported
+ *
+ **/
+ public byte[] getEncoded(String encoding)
+ throws CertificateEncodingException
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ ListIterator iter = certificates.listIterator(certificates.size());
+ while (iter.hasPrevious())
+ {
+ v.add(toASN1Object((X509Certificate)iter.previous()));
+ }
+
+ return toDEREncoded(new DERSequence(v));
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7"))
+ {
+ ContentInfo encInfo = new ContentInfo(PKCSObjectIdentifiers.data, null);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ v.add(toASN1Object((X509Certificate)certificates.get(i)));
+ }
+
+ SignedData sd = new SignedData(
+ new ASN1Integer(1),
+ new DERSet(),
+ encInfo,
+ new DERSet(v),
+ null,
+ new DERSet());
+
+ return toDEREncoded(new ContentInfo(
+ PKCSObjectIdentifiers.signedData, sd));
+ }
+ else if (encoding.equalsIgnoreCase("PEM"))
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
+
+ try
+ {
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
+ }
+
+ pWrt.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+ }
+
+ return bOut.toByteArray();
+ }
+ else
+ {
+ throw new CertificateEncodingException("unsupported encoding: " + encoding);
+ }
+ }
+
+ /**
+ * Returns the list of certificates in this certification
+ * path. The List returned must be immutable and thread-safe.
+ *
+ * @return an immutable List of Certificates (may be empty, but not null)
+ **/
+ public List getCertificates()
+ {
+ return Collections.unmodifiableList(new ArrayList(certificates));
+ }
+
+ /**
+ * Return a DERObject containing the encoded certificate.
+ *
+ * @param cert the X509Certificate object to be encoded
+ *
+ * @return the DERObject
+ **/
+ private ASN1Primitive toASN1Object(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return new ASN1InputStream(cert.getEncoded()).readObject();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Exception while encoding certificate: " + e.toString());
+ }
+ }
+
+ private byte[] toDEREncoded(ASN1Encodable obj)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException("Exception thrown: " + e);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
new file mode 100644
index 000000000..96a1529c2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
@@ -0,0 +1,134 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+class SignatureUtil
+{
+ private static final ASN1Null derNull = new DERNull();
+
+ static void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !derNull.equals(params.toASN1Primitive()))
+ {
+ try
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider().getName());
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SignatureException("cannot find provider: " + e.getMessage());
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1";
+ }
+ if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+ {
+ ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+
+ return getDigestAlgName((ASN1ObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.getAlgorithm().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ ASN1ObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
new file mode 100644
index 000000000..bd300db67
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
@@ -0,0 +1,293 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+import org.spongycastle.jce.X509Principal;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+class X509CRLEntryObject extends X509CRLEntry
+{
+ private TBSCertList.CRLEntry c;
+
+ private X500Name certificateIssuer;
+ private int hashValue;
+ private boolean isHashValueSet;
+
+ public X509CRLEntryObject(TBSCertList.CRLEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = null;
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+ * is <code>false</code> {@link #getCertificateIssuer()} will always
+ * return <code>null</code>, <code>previousCertificateIssuer</code> is
+ * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+ * has no certificate issuer CRL entry extension
+ * <code>previousCertificateIssuer</code> is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TBSCertList.CRLEntry object.
+ * @param isIndirect
+ * <code>true</code> if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CRLEntry.
+ */
+ public X509CRLEntryObject(
+ TBSCertList.CRLEntry c,
+ boolean isIndirect,
+ X500Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+ }
+
+ /**
+ * Will return true if any extensions are present and marked as critical as
+ * we currently don't handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ return extns != null && !extns.isEmpty();
+ }
+
+ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId());
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.getInstance(
+ X509ExtensionUtil.fromExtensionValue(ext)).getNames();
+ for (int i = 0; i < names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ return X500Name.getInstance(names[i].getName());
+ }
+ }
+ return null;
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ X509Principal getCertificateIssuer()
+ {
+ if (certificateIssuer == null)
+ {
+ return null;
+ }
+ try
+ {
+ return new X509Principal(certificateIssuer.getEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(e.toString());
+ }
+ }
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Cache the hashCode value - calculating it with the standard method.
+ * @return calculated hashCode.
+ */
+ public int hashCode()
+ {
+ if (!isHashValueSet)
+ {
+ hashValue = super.hashCode();
+ isHashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getUserCertificate().getValue();
+ }
+
+ public Date getRevocationDate()
+ {
+ return c.getRevocationDate().getDate();
+ }
+
+ public boolean hasExtensions()
+ {
+ return c.getExtensions() != null;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl);
+
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+ if (e.hasMoreElements())
+ {
+ buf.append(" crlEntryExtensions:").append(nl);
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(X509Extension.reasonCode))
+ {
+ buf.append(CRLReason.getInstance(DEREnumerated.getInstance(dIn.readObject()))).append(nl);
+ }
+ else if (oid.equals(X509Extension.certificateIssuer))
+ {
+ buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
new file mode 100644
index 000000000..ff88a36f0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
@@ -0,0 +1,556 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLNumber;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+class X509CRLObject
+ extends X509CRL
+{
+ private CertificateList c;
+ private String sigAlgName;
+ private byte[] sigAlgParams;
+ private boolean isIndirect;
+
+ static boolean isIndirectCRL(X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+ return idp != null
+ && IssuingDistributionPoint.getInstance(X509ExtensionUtil.fromExtensionValue(idp)).isIndirectCRL();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCRLException(
+ "Exception reading IssuingDistributionPoint", e);
+ }
+ }
+
+ public X509CRLObject(
+ CertificateList c)
+ throws CRLException
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = isIndirectCRL(this);
+ }
+ catch (Exception e)
+ {
+ throw new CRLException("CRL contents invalid: " + e);
+ }
+ }
+
+ /**
+ * Will return true if any extensions are present and marked
+ * as critical as we currently dont handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ if (extns == null)
+ {
+ return false;
+ }
+
+ extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+ return !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ if (this.getVersion() == 2)
+ {
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertList().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ verify(key, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+ {
+ throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+ }
+
+ Signature sig;
+
+ if (sigProvider != null)
+ {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+ else
+ {
+ sig = Signature.getInstance(getSigAlgName());
+ }
+
+ sig.initVerify(key);
+ sig.update(this.getTBSCertList());
+
+ if (!sig.verify(this.getSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public Principal getIssuerDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+ }
+
+ public Date getThisUpdate()
+ {
+ return c.getThisUpdate().getDate();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (c.getNextUpdate() != null)
+ {
+ return c.getNextUpdate().getDate();
+ }
+
+ return null;
+ }
+
+ private Set loadCRLEntries()
+ {
+ Set entrySet = new HashSet();
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+ X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ entrySet.add(crlEntry);
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return entrySet;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+ {
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+ if (serialNumber.equals(entry.getUserCertificate().getValue()))
+ {
+ return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getRevokedCertificates()
+ {
+ Set entrySet = loadCRLEntries();
+
+ if (!entrySet.isEmpty())
+ {
+ return Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public byte[] getTBSCertList()
+ throws CRLException
+ {
+ try
+ {
+ return c.getTBSCertList().getEncoded("DER");
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ public String getSigAlgName()
+ {
+ return sigAlgName;
+ }
+
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ {
+ byte[] tmp = new byte[sigAlgParams.length];
+
+ System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" Version: ").append(this.getVersion()).append(
+ nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN())
+ .append(nl);
+ buf.append(" This update: ").append(this.getThisUpdate())
+ .append(nl);
+ buf.append(" Next update: ").append(this.getNextUpdate())
+ .append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName())
+ .append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(
+ new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: ").append(nl);
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(
+ ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.cRLNumber))
+ {
+ buf.append(
+ new CRLNumber(DERInteger.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid.equals(Extension.deltaCRLIndicator))
+ {
+ buf.append(
+ "Base CRL: "
+ + new CRLNumber(DERInteger.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid
+ .equals(Extension.issuingDistributionPoint))
+ {
+ buf.append(
+ IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid
+ .equals(Extension.cRLDistributionPoints))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.freshestCRL))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(
+ ASN1Dump.dumpAsString(dIn.readObject()))
+ .append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ Set set = getRevokedCertificates();
+ if (set != null)
+ {
+ Iterator it = set.iterator();
+ while (it.hasNext())
+ {
+ buf.append(it.next());
+ buf.append(nl);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!cert.getType().equals("X.509"))
+ {
+ throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+ }
+
+ TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+
+ X500Name caName = c.getIssuer();
+
+ if (certs != null)
+ {
+ BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+ for (int i = 0; i < certs.length; i++)
+ {
+ if (isIndirect && certs[i].hasExtensions())
+ {
+ Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+
+ if (certs[i].getUserCertificate().getValue().equals(serial))
+ {
+ X500Name issuer;
+
+ try
+ {
+ issuer = org.spongycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new RuntimeException("Cannot process certificate");
+ }
+
+ if (!caName.equals(issuer))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
new file mode 100644
index 000000000..aa83e65de
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
@@ -0,0 +1,858 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.misc.NetscapeRevocationURL;
+import org.spongycastle.asn1.misc.VerisignCzagExtension;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.encoders.Hex;
+
+class X509CertificateObject
+ extends X509Certificate
+ implements PKCS12BagAttributeCarrier
+{
+ private org.spongycastle.asn1.x509.Certificate c;
+ private BasicConstraints basicConstraints;
+ private boolean[] keyUsage;
+ private boolean hashValueSet;
+ private int hashValue;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ public X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate c)
+ throws CertificateParsingException
+ {
+ this.c = c;
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.19");
+
+ if (bytes != null)
+ {
+ basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.15");
+ if (bytes != null)
+ {
+ DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+ bytes = bits.getBytes();
+ int length = (bytes.length * 8) - bits.getPadBits();
+
+ keyUsage = new boolean[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+ keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility
+ {
+ throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+ }
+
+ if (date.getTime() < this.getNotBefore().getTime())
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getSerialNumber().getValue();
+ }
+
+ public Principal getIssuerDN()
+ {
+ try
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public Principal getSubjectDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+ }
+
+ public Date getNotBefore()
+ {
+ return c.getStartDate().getDate();
+ }
+
+ public Date getNotAfter()
+ {
+ return c.getEndDate().getDate();
+ }
+
+ public byte[] getTBSCertificate()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ /**
+ * return a more "meaningful" representation for the signature algorithm used in
+ * the certficate.
+ */
+ public String getSigAlgName()
+ {
+ Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ if (prov != null)
+ {
+ String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ Provider[] provs = Security.getProviders();
+
+ //
+ // search every provider looking for a real algorithm
+ //
+ for (int i = 0; i != provs.length; i++)
+ {
+ String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ return this.getSigAlgOID();
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getSigAlgParams()
+ {
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ try
+ {
+ return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getIssuerUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getSubjectUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ return keyUsage;
+ }
+
+ public List getExtendedKeyUsage()
+ throws CertificateParsingException
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.37");
+
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension");
+ }
+ }
+
+ return null;
+ }
+
+ public int getBasicConstraints()
+ {
+ if (basicConstraints != null)
+ {
+ if (basicConstraints.isCA())
+ {
+ if (basicConstraints.getPathLenConstraint() == null)
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return basicConstraints.getPathLenConstraint().intValue();
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ public Collection getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+ }
+
+ public Collection getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getExtensionBytes(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+ if (ext != null)
+ {
+ return ext.getExtnValue().getOctets();
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (!ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ if (this.getVersion() == 3)
+ {
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ String oidId = oid.getId();
+
+ if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
+ || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
+ || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
+ || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
+ || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
+ || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
+ || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
+ {
+ continue;
+ }
+
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ try
+ {
+ return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ return null; // should never happen...
+ }
+ }
+
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof Certificate))
+ {
+ return false;
+ }
+
+ Certificate other = (Certificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public synchronized int hashCode()
+ {
+ if (!hashValueSet)
+ {
+ hashValue = calculateHashCode();
+ hashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ private int calculateHashCode()
+ {
+ try
+ {
+ int hashCode = 0;
+ byte[] certData = this.getEncoded();
+ for (int i = 1; i < certData.length; i++)
+ {
+ hashCode += certData[i] * i;
+ }
+ return hashCode;
+ }
+ catch (CertificateEncodingException e)
+ {
+ return 0;
+ }
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" [0] Version: ").append(this.getVersion()).append(nl);
+ buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl);
+ buf.append(" Start Date: ").append(this.getNotBefore()).append(nl);
+ buf.append(" Final Date: ").append(this.getNotAfter()).append(nl);
+ buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl);
+ buf.append(" Public Key: ").append(this.getPublicKey()).append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: \n");
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.basicConstraints))
+ {
+ buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.keyUsage))
+ {
+ buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+ {
+ buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+ {
+ buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+ {
+ buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ //buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public final void verify(
+ PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature;
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ try
+ {
+ signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ signature = Signature.getInstance(sigName);
+ }
+
+ checkSignature(key, signature);
+ }
+
+ public final void verify(
+ PublicKey key,
+ String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+ Signature signature = Signature.getInstance(sigName, sigProvider);
+
+ checkSignature(key, signature);
+ }
+
+ private void checkSignature(
+ PublicKey key,
+ Signature signature)
+ throws CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException
+ {
+ if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+ // TODO This should go after the initVerify?
+ X509SignatureUtil.setSignatureParameters(signature, params);
+
+ signature.initVerify(key);
+
+ signature.update(this.getTBSCertificate());
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new SignatureException("certificate does not verify with supplied key");
+ }
+ }
+
+ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+ {
+ return false;
+ }
+
+ if (id1.getParameters() == null)
+ {
+ if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (id2.getParameters() == null)
+ {
+ if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return id1.getParameters().equals(id2.getParameters());
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return null;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ list.add(Integers.valueOf(genName.getTagNo()));
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getEncoded());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+ list.add(addrBytes);
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(list);
+ }
+ if (temp.size() == 0)
+ {
+ return null;
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
new file mode 100644
index 000000000..6395d2e85
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -0,0 +1,125 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+class X509SignatureUtil
+{
+ private static final ASN1Null derNull = new DERNull();
+
+ static void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !derNull.equals(params))
+ {
+ /*
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+ try
+ {
+ sigParams.init(params.getDERObject().getDEREncoded());
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+
+ try
+ {
+ signature.setParameters(sigParams.getParameterSpec(PSSParameterSpec.class));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+ }
+ */
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ DERObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
new file mode 100644
index 000000000..651a471cb
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -0,0 +1,1624 @@
+package org.spongycastle.jcajce.provider.keystore.pkcs12;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.BEROutputStream;
+import org.spongycastle.asn1.DERBMPString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.AuthenticatedSafe;
+import org.spongycastle.asn1.pkcs.CertBag;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.EncryptedData;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PBES2Parameters;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.util.SecretKeyUtil;
+import org.spongycastle.jce.interfaces.BCKeyStore;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.encoders.Hex;
+
+public class PKCS12KeyStoreSpi
+ extends KeyStoreSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+ private static final int SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private static final Provider bcProvider = new BouncyCastleProvider();
+
+ private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private Hashtable localIds = new Hashtable();
+ private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private Hashtable chainCerts = new Hashtable();
+ private Hashtable keyCerts = new Hashtable();
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected SecureRandom random = new SecureRandom();
+
+ // use of final causes problems with JDK 1.2 compiler
+ private CertificateFactory certFact;
+ private ASN1ObjectIdentifier keyAlgorithm;
+ private ASN1ObjectIdentifier certAlgorithm;
+
+ private class CertId
+ {
+ byte[] id;
+
+ CertId(
+ PublicKey key)
+ {
+ this.id = createSubjectKeyId(key).getKeyIdentifier();
+ }
+
+ CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(id);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof CertId))
+ {
+ return false;
+ }
+
+ CertId cId = (CertId)o;
+
+ return Arrays.areEqual(id, cId.id);
+ }
+ }
+
+ public PKCS12KeyStoreSpi(
+ Provider provider,
+ ASN1ObjectIdentifier keyAlgorithm,
+ ASN1ObjectIdentifier certAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+
+ try
+ {
+ if (provider != null)
+ {
+ certFact = CertificateFactory.getInstance("X.509", provider.getName());
+ }
+ else
+ {
+ certFact = CertificateFactory.getInstance("X.509");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+ }
+ }
+
+ private SubjectKeyIdentifier createSubjectKeyId(
+ PublicKey pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)ASN1Primitive.fromByteArray(pubKey.getEncoded()));
+
+ return new SubjectKeyIdentifier(info);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error creating key");
+ }
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (certs.get(alias) != null || keys.get(alias) != null);
+ }
+
+ /**
+ * this is not quite complete - we should follow up on the chain, a bit
+ * tricky if a certificate appears in more than one chain...
+ */
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Key k = (Key)keys.remove(alias);
+
+ Certificate c = (Certificate)certs.remove(alias);
+
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+
+ if (k != null)
+ {
+ String id = (String)localIds.remove(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.remove(id);
+ }
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+ }
+ }
+
+ /**
+ * simply return the cert for the private key
+ */
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificate.");
+ }
+
+ Certificate c = (Certificate)certs.get(alias);
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ String id = (String)localIds.get(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.get(id);
+ }
+ else
+ {
+ c = (Certificate)keyCerts.get(alias);
+ }
+ }
+
+ return c;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration c = certs.elements();
+ Enumeration k = certs.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ c = keyCerts.elements();
+ k = keyCerts.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+ }
+
+ if (!engineIsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ Certificate c = engineGetCertificate(alias);
+
+ if (c != null)
+ {
+ Vector cs = new Vector();
+
+ while (c != null)
+ {
+ X509Certificate x509c = (X509Certificate)c;
+ Certificate nextC = null;
+
+ byte[] bytes = x509c.getExtensionValue(Extension.authorityKeyIdentifier.getId());
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(bytes);
+
+ byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+ aIn = new ASN1InputStream(authBytes);
+
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject());
+ if (id.getKeyIdentifier() != null)
+ {
+ nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+ }
+
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ Principal i = x509c.getIssuerDN();
+ Principal s = x509c.getSubjectDN();
+
+ if (!i.equals(s))
+ {
+ Enumeration e = chainCerts.keys();
+
+ while (e.hasMoreElements())
+ {
+ X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+ Principal sub = crt.getSubjectDN();
+ if (sub.equals(i))
+ {
+ try
+ {
+ x509c.verify(crt.getPublicKey());
+ nextC = crt;
+ break;
+ }
+ catch (Exception ex)
+ {
+ // continue
+ }
+ }
+ }
+ }
+ }
+
+ cs.addElement(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ Certificate[] certChain = new Certificate[cs.size()];
+
+ for (int i = 0; i != certChain.length; i++)
+ {
+ certChain[i] = (Certificate)cs.elementAt(i);
+ }
+
+ return certChain;
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ if (alias == null)
+ {
+ throw new NullPointerException("alias == null");
+ }
+ if (keys.get(alias) == null && certs.get(alias) == null)
+ {
+ return null;
+ }
+ return new Date();
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getKey.");
+ }
+
+ return (Key)keys.get(alias);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ return (certs.get(alias) != null && keys.get(alias) == null);
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ return (keys.get(alias) != null);
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ if (keys.get(alias) != null)
+ {
+ throw new KeyStoreException("There is a key entry with the name " + alias + ".");
+ }
+
+ certs.put(alias, cert);
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ throw new RuntimeException("operation not supported");
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ if (!(key instanceof PrivateKey))
+ {
+ throw new KeyStoreException("PKCS12 does not support non-PrivateKeys");
+ }
+
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ if (keys.get(alias) != null)
+ {
+ engineDeleteEntry(alias);
+ }
+
+ keys.put(alias, key);
+ if (chain != null)
+ {
+ certs.put(alias, chain[0]);
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+ }
+ }
+ }
+
+ public int engineSize()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.size();
+ }
+
+ protected PrivateKey unwrapKey(
+ AlgorithmIdentifier algId,
+ byte[] data,
+ char[] password,
+ boolean wrongPKCS12Zero)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+ try
+ {
+ if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+ {
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PrivateKey out;
+
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ SecretKey k = keyFact.generateSecret(pbeSpec);
+
+ ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+ {
+ PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
+ PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
+
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider);
+
+ SecretKey k = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), SecretKeyUtil.getKeySize(alg.getEncryptionScheme().getAlgorithm())));
+
+ Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId(), bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, new IvParameterSpec(ASN1OctetString.getInstance(alg.getEncryptionScheme().getParameters()).getOctets()));
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception unwrapping private key - " + e.toString());
+ }
+
+ throw new IOException("exception unwrapping private key - cannot recognise: " + algorithm);
+ }
+
+ protected byte[] wrapKey(
+ String algorithm,
+ Key key,
+ PKCS12PBEParams pbeParams,
+ char[] password)
+ throws IOException
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ byte[] out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+ out = cipher.wrap(key);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception encrypting data - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] cryptData(
+ boolean forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ boolean wrongPKCS12Zero,
+ byte[] data)
+ throws IOException
+ {
+ String algorithm = algId.getAlgorithm().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+ BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+
+ key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+ int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+ cipher.init(mode, key, defParams);
+ return cipher.doFinal(data);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decrypting data - " + e.toString());
+ }
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+ bufIn.mark(10);
+
+ int head = bufIn.read();
+
+ if (head != 0x30)
+ {
+ throw new IOException("stream does not represent a PKCS12 key store");
+ }
+
+ bufIn.reset();
+
+ ASN1InputStream bIn = new ASN1InputStream(bufIn);
+ ASN1Sequence obj = (ASN1Sequence)bIn.readObject();
+ Pfx bag = Pfx.getInstance(obj);
+ ContentInfo info = bag.getAuthSafe();
+ Vector chain = new Vector();
+ boolean unmarkedKey = false;
+ boolean wrongPKCS12Zero = false;
+
+ if (bag.getMacData() != null) // check the mac code
+ {
+ MacData mData = bag.getMacData();
+ DigestInfo dInfo = mData.getMac();
+ AlgorithmIdentifier algId = dInfo.getAlgorithmId();
+ byte[] salt = mData.getSalt();
+ int itCount = mData.getIterationCount().intValue();
+
+ byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
+
+ try
+ {
+ byte[] res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, false, data);
+ byte[] dig = dInfo.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ if (password.length > 0)
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ // Try with incorrect zero length password
+ res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, true, data);
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ wrongPKCS12Zero = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+ }
+
+ keys = new IgnoresCaseHashtable();
+ localIds = new Hashtable();
+
+ if (info.getContentType().equals(data))
+ {
+ bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+ AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
+ ContentInfo[] c = authSafe.getContentInfo();
+
+ for (int i = 0; i != c.length; i++)
+ {
+ if (c[i].getContentType().equals(data))
+ {
+ ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+ if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ unmarkedKey = true;
+ keys.put("unmarked", privKey);
+ }
+ }
+ else if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else
+ {
+ System.out.println("extra in data " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else if (c[i].getContentType().equals(encryptedData))
+ {
+ EncryptedData d = EncryptedData.getInstance(c[i].getContent());
+ byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
+ password, wrongPKCS12Zero, d.getContent().getOctets());
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(octets);
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+ if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else if (b.getBagId().equals(keyBag))
+ {
+ org.spongycastle.asn1.pkcs.PrivateKeyInfo kInfo = org.spongycastle.asn1.pkcs.PrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ System.out.println("extra in encryptedData " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else
+ {
+ System.out.println("extra " + c[i].getContentType().getId());
+ System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+ }
+ }
+ }
+
+ certs = new IgnoresCaseHashtable();
+ chainCerts = new Hashtable();
+ keyCerts = new Hashtable();
+
+ for (int i = 0; i != chain.size(); i++)
+ {
+ SafeBag b = (SafeBag)chain.elementAt(i);
+ CertBag cb = CertBag.getInstance(b.getBagValue());
+
+ if (!cb.getCertId().equals(x509Certificate))
+ {
+ throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
+ }
+
+ Certificate cert;
+
+ try
+ {
+ ByteArrayInputStream cIn = new ByteArrayInputStream(
+ ((ASN1OctetString)cb.getCertValue()).getOctets());
+ cert = certFact.generateCertificate(cIn);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+
+ //
+ // set the attributes
+ //
+ ASN1OctetString localId = null;
+ String alias = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Primitive attr = (ASN1Primitive)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
+ PKCS12BagAttributeCarrier bagAttr = null;
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(oid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(oid, attr);
+ }
+ }
+
+ if (oid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ }
+ else if (oid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+ if (unmarkedKey)
+ {
+ if (keyCerts.isEmpty())
+ {
+ String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+
+ keyCerts.put(name, cert);
+ keys.put(name, keys.remove("unmarked"));
+ }
+ }
+ else
+ {
+ //
+ // the local key id needs to override the friendly name
+ //
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ keyCerts.put(name, cert);
+ }
+ if (alias != null)
+ {
+ certs.put(alias, cert);
+ }
+ }
+ }
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ doStore(stream, password, false);
+ }
+
+ private void doStore(OutputStream stream, char[] password, boolean useDEREncoding)
+ throws IOException
+ {
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ //
+ // handle the key
+ //
+ ASN1EncodableVector keyS = new ASN1EncodableVector();
+
+
+ Enumeration ks = keys.keys();
+
+ while (ks.hasMoreElements())
+ {
+ byte[] kSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(kSalt);
+
+ String name = (String)ks.nextElement();
+ PrivateKey privKey = (PrivateKey)keys.get(name);
+ PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+ byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+ AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+ boolean attrSet = false;
+ ASN1EncodableVector kName = new ASN1EncodableVector();
+
+ if (privKey instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ Certificate ct = engineGetCertificate(name);
+
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+
+ kSeq.add(oid);
+ kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+ attrSet = true;
+
+ kName.add(new DERSequence(kSeq));
+ }
+ }
+
+ if (!attrSet)
+ {
+ //
+ // set a default friendly name (from the key id) and local id
+ //
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+ Certificate ct = engineGetCertificate(name);
+
+ kSeq.add(pkcs_9_at_localKeyId);
+ kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+ kName.add(new DERSequence(kSeq));
+
+ kSeq = new ASN1EncodableVector();
+
+ kSeq.add(pkcs_9_at_friendlyName);
+ kSeq.add(new DERSet(new DERBMPString(name)));
+
+ kName.add(new DERSequence(kSeq));
+ }
+
+ SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
+ keyS.add(kBag);
+ }
+
+ byte[] keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
+ BEROctetString keyString = new BEROctetString(keySEncoded);
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(cSalt);
+
+ ASN1EncodableVector certSeq = new ASN1EncodableVector();
+ PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+ Hashtable doneCerts = new Hashtable();
+
+ Enumeration cs = keys.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String name = (String)cs.nextElement();
+ Certificate cert = engineGetCertificate(name);
+ boolean cAttrSet = false;
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_localKeyId);
+ fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+ fName.add(new DERSequence(fSeq));
+
+ fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(name)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = certs.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String certId = (String)cs.nextElement();
+ Certificate cert = (Certificate)certs.get(certId);
+ boolean cAttrSet = false;
+
+ if (keys.get(certId) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(certId))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(certId)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = chainCerts.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ CertId certId = (CertId)cs.nextElement();
+ Certificate cert = (Certificate)chainCerts.get(certId);
+
+ if (doneCerts.get(cert) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+ }
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
+ byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
+ EncryptedData cInfo = new EncryptedData(data, cAlgId, new BEROctetString(certBytes));
+
+ ContentInfo[] info = new ContentInfo[]
+ {
+ new ContentInfo(data, keyString),
+ new ContentInfo(encryptedData, cInfo.toASN1Primitive())
+ };
+
+ AuthenticatedSafe auth = new AuthenticatedSafe(info);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream asn1Out;
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(bOut);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(bOut);
+ }
+
+ asn1Out.writeObject(auth);
+
+ byte[] pkg = bOut.toByteArray();
+
+ ContentInfo mainInfo = new ContentInfo(data, new BEROctetString(pkg));
+
+ //
+ // create the mac
+ //
+ byte[] mSalt = new byte[20];
+ int itCount = MIN_ITERATIONS;
+
+ random.nextBytes(mSalt);
+
+ byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+ MacData mData;
+
+ try
+ {
+ byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, DERNull.INSTANCE);
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mSalt, itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(stream);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(stream);
+ }
+
+ asn1Out.writeObject(pfx);
+ }
+
+ private static byte[] calculatePbeMac(
+ ASN1ObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ boolean wrongPkcs12Zero,
+ byte[] data)
+ throws Exception
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+ key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
+
+ Mac mac = Mac.getInstance(oid.getId(), bcProvider);
+ mac.init(key, defParams);
+ mac.update(data);
+ return mac.doFinal();
+ }
+
+ public static class BCPKCS12KeyStore
+ extends PKCS12KeyStoreSpi
+ {
+ public BCPKCS12KeyStore()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class BCPKCS12KeyStore3DES
+ extends PKCS12KeyStoreSpi
+ {
+ public BCPKCS12KeyStore3DES()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore
+ extends PKCS12KeyStoreSpi
+ {
+ public DefPKCS12KeyStore()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore3DES
+ extends PKCS12KeyStoreSpi
+ {
+ public DefPKCS12KeyStore3DES()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ private static class IgnoresCaseHashtable
+ {
+ private Hashtable orig = new Hashtable();
+ private Hashtable keys = new Hashtable();
+
+ public void put(String key, Object value)
+ {
+ String lower = (key == null) ? null : Strings.toLowerCase(key);
+ String k = (String)keys.get(lower);
+ if (k != null)
+ {
+ orig.remove(k);
+ }
+
+ keys.put(lower, key);
+ orig.put(key, value);
+ }
+
+ public Enumeration keys()
+ {
+ return orig.keys();
+ }
+
+ public Object remove(String alias)
+ {
+ String k = (String)keys.remove(alias == null ? null : Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.remove(k);
+ }
+
+ public Object get(String alias)
+ {
+ String k = (String)keys.get(alias == null ? null : Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.get(k);
+ }
+
+ public Enumeration elements()
+ {
+ return orig.elements();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
new file mode 100644
index 000000000..34ce128e9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -0,0 +1,1029 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Method;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+
+import org.spongycastle.asn1.cms.GCMParameters;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DataLengthException;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.OutputLengthException;
+import org.spongycastle.crypto.modes.AEADBlockCipher;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.CCMBlockCipher;
+import org.spongycastle.crypto.modes.CFBBlockCipher;
+import org.spongycastle.crypto.modes.CTSBlockCipher;
+import org.spongycastle.crypto.modes.EAXBlockCipher;
+import org.spongycastle.crypto.modes.GCFBBlockCipher;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.crypto.modes.GOFBBlockCipher;
+import org.spongycastle.crypto.modes.OCBBlockCipher;
+import org.spongycastle.crypto.modes.OFBBlockCipher;
+import org.spongycastle.crypto.modes.OpenPGPCFBBlockCipher;
+import org.spongycastle.crypto.modes.PGPCFBBlockCipher;
+import org.spongycastle.crypto.modes.SICBlockCipher;
+import org.spongycastle.crypto.paddings.BlockCipherPadding;
+import org.spongycastle.crypto.paddings.ISO10126d2Padding;
+import org.spongycastle.crypto.paddings.ISO7816d4Padding;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.crypto.paddings.TBCPadding;
+import org.spongycastle.crypto.paddings.X923Padding;
+import org.spongycastle.crypto.paddings.ZeroBytePadding;
+import org.spongycastle.crypto.params.AEADParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.params.ParametersWithSBox;
+import org.spongycastle.crypto.params.RC2Parameters;
+import org.spongycastle.crypto.params.RC5Parameters;
+import org.spongycastle.jcajce.spec.GOST28147ParameterSpec;
+import org.spongycastle.jcajce.spec.RepeatedSecretKeySpec;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class BaseBlockCipher
+ extends BaseWrapCipher
+ implements PBE
+{
+ private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
+
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ RC2ParameterSpec.class,
+ RC5ParameterSpec.class,
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ GOST28147ParameterSpec.class,
+ gcmSpecClass
+ };
+
+ private BlockCipher baseEngine;
+ private BlockCipherProvider engineProvider;
+ private GenericBlockCipher cipher;
+ private ParametersWithIV ivParam;
+ private AEADParameters aeadParams;
+
+ private int ivLength = 0;
+
+ private boolean padded;
+
+ private PBEParameterSpec pbeSpec = null;
+ private String pbeAlgorithm = null;
+
+ private String modeName = null;
+
+ private static Class lookup(String className)
+ {
+ try
+ {
+ Class def = BaseBlockCipher.class.getClassLoader().loadClass(className);
+
+ return def;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ protected BaseBlockCipher(
+ BlockCipher engine)
+ {
+ baseEngine = engine;
+
+ cipher = new BufferedGenericBlockCipher(engine);
+ }
+
+ protected BaseBlockCipher(
+ BlockCipherProvider provider)
+ {
+ baseEngine = provider.get();
+ engineProvider = provider;
+
+ cipher = new BufferedGenericBlockCipher(provider.get());
+ }
+
+ protected BaseBlockCipher(
+ AEADBlockCipher engine)
+ {
+ baseEngine = engine.getUnderlyingCipher();
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(engine);
+ }
+
+ protected BaseBlockCipher(
+ org.spongycastle.crypto.BlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine;
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected BaseBlockCipher(
+ BufferedBlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine.getUnderlyingCipher();
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return baseEngine.getBlockSize();
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return (ivParam != null) ? ivParam.getIV() : null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length * 8;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return cipher.getOutputSize(inputLen);
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (pbeSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(pbeSpec);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ else if (ivParam != null)
+ {
+ String name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+ if (name.indexOf('/') >= 0)
+ {
+ name = name.substring(0, name.indexOf('/'));
+ }
+
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(ivParam.getIV());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ else if (aeadParams != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("GCM", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize()).getEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ modeName = Strings.toUpperCase(mode);
+
+ if (modeName.equals("ECB"))
+ {
+ ivLength = 0;
+ cipher = new BufferedGenericBlockCipher(baseEngine);
+ }
+ else if (modeName.equals("CBC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(
+ new CBCBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("OFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("CFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("PGP"))
+ {
+ boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
+
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(
+ new PGPCFBBlockCipher(baseEngine, inlineIV));
+ }
+ else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+ {
+ ivLength = 0;
+ cipher = new BufferedGenericBlockCipher(
+ new OpenPGPCFBBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("SIC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (ivLength < 16)
+ {
+ throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+ }
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CTR"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("GOFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new GOFBBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("GCFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new GCFBBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CTS"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CCM"))
+ {
+ ivLength = 13; // CCM nonce 7..13 bytes
+ cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("OCB"))
+ {
+ if (engineProvider != null)
+ {
+ // Nonce restricted to max 120 bits over 128 bit block cipher since draft-irtf-cfrg-ocb-03
+ ivLength = 15;
+ cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
+ }
+ else
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+ }
+ else if (modeName.startsWith("EAX"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("GCM"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine));
+ }
+ else
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String paddingName = Strings.toUpperCase(padding);
+
+ if (paddingName.equals("NOPADDING"))
+ {
+ if (cipher.wrapOnNoPadding())
+ {
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ }
+ else if (paddingName.equals("WITHCTS"))
+ {
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ else
+ {
+ padded = true;
+
+ if (isAEADModeName(modeName))
+ {
+ throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes.");
+ }
+ else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else if (paddingName.equals("ZEROBYTEPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
+ }
+ else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
+ }
+ else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
+ }
+ else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
+ }
+ else if (paddingName.equals("TBCPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
+ }
+ else
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ this.pbeSpec = null;
+ this.pbeAlgorithm = null;
+ this.engineParams = null;
+ this.aeadParams = null;
+
+ //
+ // basic key check
+ //
+ if (!(key instanceof SecretKey))
+ {
+ throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+ }
+
+ //
+ // for RC5-64 we must have some default parameters
+ //
+ if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
+ {
+ throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
+ }
+
+ //
+ // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+ //
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (k.getOID() != null)
+ {
+ pbeAlgorithm = k.getOID().getId();
+ }
+ else
+ {
+ pbeAlgorithm = k.getAlgorithm();
+ }
+
+ if (k.getParam() != null)
+ {
+ param = k.getParam();
+ if (params instanceof IvParameterSpec)
+ {
+ IvParameterSpec iv = (IvParameterSpec)params;
+
+ param = new ParametersWithIV(param, iv.getIV());
+ }
+ else if (params instanceof GOST28147ParameterSpec)
+ {
+ // need to pick up IV and SBox.
+ GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+
+ param = new ParametersWithSBox(param, gost28147Param.getSbox());
+
+ if (gost28147Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, gost28147Param.getIV());
+ }
+ }
+ }
+ else if (params instanceof PBEParameterSpec)
+ {
+ pbeSpec = (PBEParameterSpec)params;
+ param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+
+ if (param instanceof ParametersWithIV)
+ {
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ if (ivLength != 0)
+ {
+ IvParameterSpec p = (IvParameterSpec)params;
+
+ if (p.getIV().length != ivLength && !isAEADModeName(modeName))
+ {
+ throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+ }
+
+ if (key instanceof RepeatedSecretKeySpec)
+ {
+ param = new ParametersWithIV(null, p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else
+ {
+ if (modeName != null && modeName.equals("ECB"))
+ {
+ throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
+ }
+
+ param = new KeyParameter(key.getEncoded());
+ }
+ }
+ else if (params instanceof GOST28147ParameterSpec)
+ {
+ GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+
+ param = new ParametersWithSBox(
+ new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+
+ if (gost28147Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, gost28147Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params instanceof RC2ParameterSpec)
+ {
+ RC2ParameterSpec rc2Param = (RC2ParameterSpec)params;
+
+ param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+
+ if (rc2Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, rc2Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params instanceof RC5ParameterSpec)
+ {
+ RC5ParameterSpec rc5Param = (RC5ParameterSpec)params;
+
+ param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+ if (baseEngine.getAlgorithmName().startsWith("RC5"))
+ {
+ if (baseEngine.getAlgorithmName().equals("RC5-32"))
+ {
+ if (rc5Param.getWordSize() != 32)
+ {
+ throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+ }
+ }
+ else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+ {
+ if (rc5Param.getWordSize() != 64)
+ {
+ throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+ }
+ }
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+ }
+ if ((rc5Param.getIV() != null) && (ivLength != 0))
+ {
+ param = new ParametersWithIV(param, rc5Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (gcmSpecClass != null && gcmSpecClass.isInstance(params))
+ {
+ if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
+ {
+ throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes.");
+ }
+
+ try
+ {
+ Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+ Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+ if (key instanceof RepeatedSecretKeySpec)
+ {
+ param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+ }
+ else
+ {
+ param = aeadParams = new AEADParameters(new KeyParameter(key.getEncoded()), ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
+ }
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ }
+
+ if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters))
+ {
+ SecureRandom ivRandom = random;
+
+ if (ivRandom == null)
+ {
+ ivRandom = new SecureRandom();
+ }
+
+ if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+ {
+ byte[] iv = new byte[ivLength];
+
+ ivRandom.nextBytes(iv);
+ param = new ParametersWithIV(param, iv);
+ ivParam = (ParametersWithIV)param;
+ }
+ else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
+ {
+ throw new InvalidAlgorithmParameterException("no IV set when one expected");
+ }
+ }
+
+ if (random != null && padded)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ try
+ {
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ for (int i = 0; i != availableSpecs.length; i++)
+ {
+ if (availableSpecs[i] == null)
+ {
+ continue;
+ }
+
+ try
+ {
+ paramSpec = params.getParameterSpec(availableSpecs[i]);
+ break;
+ }
+ catch (Exception e)
+ {
+ // try again if possible
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineInit(opmode, key, paramSpec, random);
+
+ engineParams = 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());
+ }
+ }
+
+ protected void engineUpdateAAD(byte[] input, int offset, int length)
+ {
+ cipher.updateAAD(input, offset, length);
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ int length = cipher.getUpdateOutputSize(inputLen);
+
+ if (length > 0)
+ {
+ byte[] out = new byte[length];
+
+ int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+ if (len == 0)
+ {
+ return null;
+ }
+ else if (len != out.length)
+ {
+ byte[] tmp = new byte[len];
+
+ System.arraycopy(out, 0, tmp, 0, len);
+
+ return tmp;
+ }
+
+ return out;
+ }
+
+ cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ try
+ {
+ return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+ catch (DataLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ int len = 0;
+ byte[] tmp = new byte[engineGetOutputSize(inputLen)];
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+ }
+
+ try
+ {
+ len += cipher.doFinal(tmp, len);
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ if (len == tmp.length)
+ {
+ return tmp;
+ }
+
+ byte[] out = new byte[len];
+
+ System.arraycopy(tmp, 0, out, 0, len);
+
+ return out;
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+ {
+ try
+ {
+ int len = 0;
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ return (len + cipher.doFinal(output, outputOffset + len));
+ }
+ catch (OutputLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ private boolean isAEADModeName(
+ String modeName)
+ {
+ return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName) || "OCB".equals(modeName);
+ }
+
+ /*
+ * The ciphers that inherit from us.
+ */
+
+ static private interface GenericBlockCipher
+ {
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ public boolean wrapOnNoPadding();
+
+ public String getAlgorithmName();
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher();
+
+ public int getOutputSize(int len);
+
+ public int getUpdateOutputSize(int len);
+
+ public void updateAAD(byte[] input, int offset, int length);
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException;
+ }
+
+ private static class BufferedGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private BufferedBlockCipher cipher;
+
+ BufferedGenericBlockCipher(BufferedBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ BufferedGenericBlockCipher(org.spongycastle.crypto.BlockCipher cipher)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher);
+ }
+
+ BufferedGenericBlockCipher(org.spongycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher, padding);
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return !(cipher instanceof CTSBlockCipher);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public void updateAAD(byte[] input, int offset, int length)
+ {
+ throw new UnsupportedOperationException("AAD is not supported in the current mode.");
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+
+ private static class AEADGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private AEADBlockCipher cipher;
+
+ AEADGenericBlockCipher(AEADBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return false;
+ }
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public void updateAAD(byte[] input, int offset, int length)
+ {
+ cipher.processAADBytes(input, offset, length);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java
new file mode 100644
index 000000000..c2343e109
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java
@@ -0,0 +1,229 @@
+package org.spongycastle.jce;
+
+import java.io.UnsupportedEncodingException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * Utility class to allow conversion of EC key parameters to explicit from named
+ * curves and back (where possible).
+ */
+public class ECKeyUtil
+{
+ /**
+ * Convert a passed in public EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param providerName provider name to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ */
+ public static PublicKey publicToExplicitParameters(PublicKey key, String providerName)
+ throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ Provider provider = Security.getProvider(providerName);
+
+ if (provider == null)
+ {
+ throw new NoSuchProviderException("cannot find provider: " + providerName);
+ }
+
+ return publicToExplicitParameters(key, provider);
+ }
+
+ /**
+ * Convert a passed in public EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param provider provider to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ */
+ public static PublicKey publicToExplicitParameters(PublicKey key, Provider provider)
+ throws IllegalArgumentException, NoSuchAlgorithmException
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded()));
+
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ throw new IllegalArgumentException("cannot convert GOST key to explicit parameters.");
+ }
+ else
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ X9ECParameters curveParams;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+ curveParams = ECUtil.getNamedCurveByOid(oid);
+ // ignore seed value due to JDK bug
+ curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH());
+ }
+ else
+ {
+ return key; // already explicit
+ }
+
+ params = new X962Parameters(curveParams);
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.getPublicKeyData().getBytes());
+
+ KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider.getName());
+
+ return keyFact.generatePublic(new X509EncodedKeySpec(info.getEncoded()));
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ { // shouldn't really happen...
+ throw new UnexpectedException(e);
+ }
+ }
+
+ /**
+ * Convert a passed in private EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param providerName provider name to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ */
+ public static PrivateKey privateToExplicitParameters(PrivateKey key, String providerName)
+ throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ Provider provider = Security.getProvider(providerName);
+
+ if (provider == null)
+ {
+ throw new NoSuchProviderException("cannot find provider: " + providerName);
+ }
+
+ return privateToExplicitParameters(key, provider);
+ }
+
+ /**
+ * Convert a passed in private EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param provider provider to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ */
+ public static PrivateKey privateToExplicitParameters(PrivateKey key, Provider provider)
+ throws IllegalArgumentException, NoSuchAlgorithmException
+ {
+ try
+ {
+ PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded()));
+
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ throw new UnsupportedEncodingException("cannot convert GOST key to explicit parameters.");
+ }
+ else
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ X9ECParameters curveParams;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+ curveParams = ECUtil.getNamedCurveByOid(oid);
+ // ignore seed value due to JDK bug
+ curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH());
+ }
+ else
+ {
+ return key; // already explicit
+ }
+
+ params = new X962Parameters(curveParams);
+
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.parsePrivateKey());
+
+ KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider.getName());
+
+ return keyFact.generatePrivate(new PKCS8EncodedKeySpec(info.getEncoded()));
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ { // shouldn't really happen
+ throw new UnexpectedException(e);
+ }
+ }
+
+ private static class UnexpectedException
+ extends RuntimeException
+ {
+ private Throwable cause;
+
+ UnexpectedException(Throwable cause)
+ {
+ super(cause.toString());
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java
new file mode 100644
index 000000000..42f46648f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jce;
+
+import org.spongycastle.jce.cert.CertStoreParameters;
+import java.util.Collection;
+
+public class MultiCertStoreParameters
+ implements CertStoreParameters
+{
+ private Collection certStores;
+ private boolean searchAllStores;
+
+ /**
+ * Create a parameters object which specifies searching of all the passed in stores.
+ *
+ * @param certStores CertStores making up the multi CertStore
+ */
+ public MultiCertStoreParameters(Collection certStores)
+ {
+ this(certStores, true);
+ }
+
+ /**
+ * Create a parameters object which can be to used to make a multi store made up
+ * of the passed in CertStores. If the searchAllStores parameter is false, any search on
+ * the multi-store will terminate as soon as a search query produces a result.
+ *
+ * @param certStores CertStores making up the multi CertStore
+ * @param searchAllStores true if all CertStores should be searched on request, false if a result
+ * should be returned on the first successful CertStore query.
+ */
+ public MultiCertStoreParameters(Collection certStores, boolean searchAllStores)
+ {
+ this.certStores = certStores;
+ this.searchAllStores = searchAllStores;
+ }
+
+ public Collection getCertStores()
+ {
+ return certStores;
+ }
+
+ public boolean getSearchAllStores()
+ {
+ return searchAllStores;
+ }
+
+ public Object clone()
+ {
+ return this;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java
new file mode 100644
index 000000000..051f2d41f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java
@@ -0,0 +1,583 @@
+package org.spongycastle.jce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.CertificationRequest;
+import org.spongycastle.asn1.pkcs.CertificationRequestInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+/**
+ * A class for verifying and creating PKCS10 Certification requests.
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ * signature BIT STRING
+ * }
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version INTEGER { v1(0) } (v1,...),
+ * subject Name,
+ * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ * attributes [0] Attributes{{ CRIAttributes }}
+ * }
+ *
+ * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
+ *
+ * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ * type ATTRIBUTE.&id({IOSet}),
+ * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ * }
+ * </pre>
+ * @deprecated use classes in org.spongycastle.pkcs.
+ */
+public class PKCS10CertificationRequest
+ extends CertificationRequest
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Hashtable keyAlgorithms = new Hashtable();
+ private static Hashtable oids = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("RSAWITHSHA1", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // reverse mappings
+ //
+ oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+
+ oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+ oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+
+ //
+ // key types
+ //
+ keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+
+ //
+ // RFC 4491
+ //
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull());
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull());
+ params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull());
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, new DERNull());
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, new DERNull());
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ private static ASN1Sequence toDERSequence(
+ byte[] bytes)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+
+ return (ASN1Sequence)dIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("badly encoded request");
+ }
+ }
+
+ /**
+ * construct a PKCS10 certification request from a DER encoded
+ * byte stream.
+ */
+ public PKCS10CertificationRequest(
+ byte[] bytes)
+ {
+ super(toDERSequence(bytes));
+ }
+
+ public PKCS10CertificationRequest(
+ ASN1Sequence sequence)
+ {
+ super(sequence);
+ }
+
+ /**
+ * create a PKCS10 certfication request using the BC provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X509Name subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ this(signatureAlgorithm, subject, key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+
+ /**
+ * create a PKCS10 certfication request using the named provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X509Name subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ String algorithmName = Strings.toUpperCase(signatureAlgorithm);
+ DERObjectIdentifier sigOID = (DERObjectIdentifier)algorithms.get(algorithmName);
+
+ if (sigOID == null)
+ {
+ try
+ {
+ sigOID = new DERObjectIdentifier(algorithmName);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+ }
+
+ if (subject == null)
+ {
+ throw new IllegalArgumentException("subject must not be null");
+ }
+
+ if (key == null)
+ {
+ throw new IllegalArgumentException("public key must not be null");
+ }
+
+ if (noParams.contains(sigOID))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID);
+ }
+ else if (params.containsKey(algorithmName))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);
+ }
+
+ try
+ {
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(key.getEncoded());
+ this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo(seq), attributes);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't encode public key");
+ }
+
+ Signature sig;
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm);
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+
+ sig.initSign(signingKey);
+
+ try
+ {
+ sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("exception encoding TBS cert request - " + e);
+ }
+
+ this.sigBits = new DERBitString(sig.sign());
+ }
+
+ /**
+ * return the public key associated with the certification request -
+ * the public key is created using the BC provider.
+ */
+ public PublicKey getPublicKey()
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
+ {
+ return getPublicKey(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public PublicKey getPublicKey(
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException
+ {
+ SubjectPublicKeyInfo subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
+
+
+ try
+ {
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
+ AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithm();
+ try
+ {
+ if (provider == null)
+ {
+ return KeyFactory.getInstance(keyAlg.getAlgorithm().getId()).generatePublic(xspec);
+ }
+ else
+ {
+ return KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), provider).generatePublic(xspec);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (keyAlgorithms.get(keyAlg.getObjectId()) != null)
+ {
+ String keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getObjectId());
+
+ if (provider == null)
+ {
+ return KeyFactory.getInstance(keyAlgorithm).generatePublic(xspec);
+ }
+ else
+ {
+ return KeyFactory.getInstance(keyAlgorithm, provider).generatePublic(xspec);
+ }
+ }
+
+ throw e;
+ }
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new InvalidKeyException("error decoding public key");
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeyException("error decoding public key");
+ }
+ }
+
+ /**
+ * verify the request using the BC provider.
+ */
+ public boolean verify()
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ return verify(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ /**
+ * verify the request using the passed in provider.
+ */
+ public boolean verify(
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ return verify(this.getPublicKey(provider), provider);
+ }
+
+ /**
+ * verify the request using the passed in public key and the provider..
+ */
+ public boolean verify(
+ PublicKey pubKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ try
+ {
+ if (provider == null)
+ {
+ sig = Signature.getInstance(getSignatureName(sigAlgId));
+ }
+ else
+ {
+ sig = Signature.getInstance(getSignatureName(sigAlgId), provider);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(sigAlgId.getObjectId()) != null)
+ {
+ String signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId());
+
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm);
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ setSignatureParameters(sig, sigAlgId.getParameters(), provider);
+
+ sig.initVerify(pubKey);
+
+ try
+ {
+ sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("exception encoding TBS cert request - " + e);
+ }
+
+ return sig.verify(sigBits.getBytes());
+ }
+
+ /**
+ * return a DER encoded byte array representing this object
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ return this.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ private void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), provider);
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ private static String getDigestAlgName(
+ DERObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java
new file mode 100644
index 000000000..0cafff5c4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java
@@ -0,0 +1,41 @@
+package org.spongycastle.jce.cert;
+
+import java.security.cert.CRL;
+
+/**
+ * A selector that defines a set of criteria for selecting <code>CRL</code>s.
+ * Classes that implement this interface are often used to specify
+ * which <code>CRL</code>s should be retrieved from a <code>CertStore</code>.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this interface are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CRL
+ * @see CertStore
+ * @see CertStore#getCRLs
+ **/
+public interface CRLSelector extends Cloneable
+{
+ /**
+ * Decides whether a <code>CRL</code> should be selected.
+ *
+ * @param crl the <code>CRL</code> to be checked
+ *
+ * @return <code>true</code> if the <code>CRL</code> should be selected,
+ * <code>false</code> otherwise
+ */
+ public boolean match(CRL crl);
+
+ /**
+ * Makes a copy of this <code>CRLSelector</code>. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this <code>CRLSelector</code>
+ */
+ public Object clone();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java
new file mode 100644
index 000000000..34f9c6282
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java
@@ -0,0 +1,296 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * An immutable sequence of certificates (a certification path).<br />
+ * <br />
+ * This is an abstract class that defines the methods common to all CertPaths.
+ * Subclasses can handle different kinds of certificates (X.509, PGP, etc.).<br />
+ * <br />
+ * All CertPath objects have a type, a list of Certificates, and one or more
+ * supported encodings. Because the CertPath class is immutable, a CertPath
+ * cannot change in any externally visible way after being constructed. This
+ * stipulation applies to all public fields and methods of this class and any
+ * added or overridden by subclasses.<br />
+ * <br />
+ * The type is a String that identifies the type of Certificates in the
+ * certification path. For each certificate cert in a certification path
+ * certPath, cert.getType().equals(certPath.getType()) must be true.<br />
+ * <br />
+ * The list of Certificates is an ordered List of zero or more Certificates.
+ * This List and all of the Certificates contained in it must be immutable.<br />
+ * <br />
+ * Each CertPath object must support one or more encodings so that the object
+ * can be translated into a byte array for storage or transmission to other
+ * parties. Preferably, these encodings should be well-documented standards
+ * (such as PKCS#7). One of the encodings supported by a CertPath is considered
+ * the default encoding. This encoding is used if no encoding is explicitly
+ * requested (for the {@link #getEncoded()} method, for instance).<br />
+ * <br />
+ * All CertPath objects are also Serializable. CertPath objects are resolved
+ * into an alternate {@link CertPathRep} object during serialization. This
+ * allows a CertPath object to be serialized into an equivalent representation
+ * regardless of its underlying implementation.<br />
+ * <br />
+ * CertPath objects can be created with a CertificateFactory or they can be
+ * returned by other classes, such as a CertPathBuilder.<br />
+ * <br />
+ * By convention, X.509 CertPaths (consisting of X509Certificates), are ordered
+ * starting with the target certificate and ending with a certificate issued by
+ * the trust anchor. That is, the issuer of one certificate is the subject of
+ * the following one. The certificate representing the
+ * {@link TrustAnchor TrustAnchor} should not be included in the certification
+ * path. Unvalidated X.509 CertPaths may not follow these conventions. PKIX
+ * CertPathValidators will detect any departure from these conventions that
+ * cause the certification path to be invalid and throw a
+ * CertPathValidatorException.<br />
+ * <br />
+ * <strong>Concurrent Access</strong><br />
+ * <br />
+ * All CertPath objects must be thread-safe. That is, multiple threads may
+ * concurrently invoke the methods defined in this class on a single CertPath
+ * object (or more than one) with no ill effects. This is also true for the List
+ * returned by CertPath.getCertificates.<br />
+ * <br />
+ * Requiring CertPath objects to be immutable and thread-safe allows them to be
+ * passed around to various pieces of code without worrying about coordinating
+ * access. Providing this thread-safety is generally not difficult, since the
+ * CertPath and List objects in question are immutable.
+ *
+ * @see CertificateFactory
+ * @see CertPathBuilder
+ */
+public abstract class CertPath extends Object implements Serializable
+{
+ private String type;
+
+ /**
+ * Alternate <code>CertPath</code> class for serialization.
+ */
+ protected static class CertPathRep implements Serializable
+ {
+ private String type;
+
+ private byte[] data;
+
+ /**
+ * Creates a <code>CertPathRep</code> with the specified type and
+ * encoded form of a certification path.
+ *
+ * @param type
+ * the standard name of a CertPath
+ * @param typedata
+ * the encoded form of the certification path
+ */
+ protected CertPathRep(String type, byte[] data)
+ {
+ this.type = type;
+ this.data = data;
+ }
+
+ /**
+ * Returns a CertPath constructed from the type and data.
+ *
+ * @return the resolved CertPath object
+ * @exception ObjectStreamException
+ * if a CertPath could not be constructed
+ */
+ protected Object readResolve() throws ObjectStreamException
+ {
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(data);
+ CertificateFactory cf = CertificateFactory.getInstance(type);
+ return cf.generateCertPath(inStream);
+ }
+ catch (CertificateException ce)
+ {
+ throw new NotSerializableException(
+ " java.security.cert.CertPath: " + type);
+ }
+ }
+ }
+
+ /**
+ * Creates a CertPath of the specified type. This constructor is protected
+ * because most users should use a CertificateFactory to create CertPaths.
+ *
+ * @param type
+ * the standard name of the type of Certificatesin this path
+ */
+ protected CertPath(String type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * Returns the type of Certificates in this certification path. This is the
+ * same string that would be returned by
+ * {@link java.security.cert.Certificate#getType()} for all Certificates in
+ * the certification path.
+ *
+ * @return the type of Certificates in this certification path (never null)
+ */
+ public String getType()
+ {
+ return type;
+ }
+
+ /**
+ * Returns an iteration of the encodings supported by this certification
+ * path, with the default encoding first. Attempts to modify the returned
+ * Iterator via its remove method result in an
+ * UnsupportedOperationException.
+ *
+ * @return an Iterator over the names of the supported encodings (as
+ * Strings)
+ */
+ public abstract Iterator getEncodings();
+
+ /**
+ * Compares this certification path for equality with the specified object.
+ * Two CertPaths are equal if and only if their types are equal and their
+ * certificate Lists (and by implication the Certificates in those Lists)
+ * are equal. A CertPath is never equal to an object that is not a CertPath.<br />
+ * <br />
+ * This algorithm is implemented by this method. If it is overridden, the
+ * behavior specified here must be maintained.
+ *
+ * @param other
+ * the object to test for equality with this certification path
+ *
+ * @return true if the specified object is equal to this certification path,
+ * false otherwise
+ *
+ * @see Object#hashCode() Object.hashCode()
+ */
+ public boolean equals(Object other)
+ {
+ if (!(other instanceof CertPath))
+ {
+ return false;
+ }
+
+ CertPath otherCertPath = (CertPath)other;
+ if (!getType().equals(otherCertPath.getType()))
+ {
+ return false;
+ }
+ return getCertificates().equals(otherCertPath.getCertificates());
+ }
+
+ /**
+ * Returns the hashcode for this certification path. The hash code of a
+ * certification path is defined to be the result of the following
+ * calculation:
+ *
+ * <pre>
+ * hashCode = path.getType().hashCode();
+ * hashCode = 31 * hashCode + path.getCertificates().hashCode();
+ * </pre>
+ *
+ * This ensures that path1.equals(path2) implies that
+ * path1.hashCode()==path2.hashCode() for any two certification paths, path1
+ * and path2, as required by the general contract of Object.hashCode.
+ *
+ * @return The hashcode value for this certification path
+ *
+ * @see #equals(Object)
+ */
+ public int hashCode()
+ {
+ return getType().hashCode() * 31 + getCertificates().hashCode();
+ }
+
+ /**
+ * Returns a string representation of this certification path. This calls
+ * the toString method on each of the Certificates in the path.
+ *
+ * @return a string representation of this certification path
+ */
+ public String toString()
+ {
+ StringBuffer s = new StringBuffer();
+ List certs = getCertificates();
+ ListIterator iter = certs.listIterator();
+ s.append('\n').append(getType()).append(" Cert Path: length = ").append(certs.size())
+ .append("\n[\n");
+ while (iter.hasNext())
+ {
+ s
+ .append("=========================================================Certificate ")
+ .append(iter.nextIndex()).append('\n');
+ s.append(iter.next()).append('\n');
+ s
+ .append("========================================================Certificate end\n\n\n");
+ }
+ s.append("\n]");
+ return s.toString();
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using the default
+ * encoding.
+ *
+ * @return the encoded bytes
+ *
+ * @exception CertificateEncodingException
+ * if an encoding error occurs
+ */
+ public abstract byte[] getEncoded() throws CertificateEncodingException;
+
+ /**
+ * Returns the encoded form of this certification path, using the specified
+ * encoding.
+ *
+ * @param encoding
+ * the name of the encoding to use
+ *
+ * @return the encoded bytes
+ *
+ * @exception CertificateEncodingException
+ * if an encoding error occurs or the encoding requested is
+ * not supported
+ */
+ public abstract byte[] getEncoded(String encoding)
+ throws CertificateEncodingException;
+
+ /**
+ * Returns the list of certificates in this certification path. The List
+ * returned must be immutable and thread-safe.
+ *
+ * @return an immutable List of Certificates (may be empty, but not null)
+ */
+ public abstract List getCertificates();
+
+ /**
+ * Replaces the CertPath to be serialized with a CertPathRep object.
+ *
+ * @return the CertPathRep to be serialized
+ *
+ * @exception ObjectStreamException
+ * if a CertPathRep object representing this certification
+ * path could not be created
+ */
+ protected Object writeReplace() throws ObjectStreamException
+ {
+ try
+ {
+ return new CertPathRep(getType(), getEncoded());
+ }
+ catch (CertificateException ce)
+ {
+ throw new NotSerializableException(" java.security.cert.CertPath: "
+ + getType());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java
new file mode 100644
index 000000000..54585689d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java
@@ -0,0 +1,255 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+/**
+ * A class for building certification paths (also known as certificate chains).<br />
+ * <br />
+ * This class uses a provider-based architecture, as described in the Java
+ * Cryptography Architecture. To create a <code>CertPathBuilder</code>, call
+ * one of the static <code>getInstance</code> methods, passing in the
+ * algorithm name of the CertPathBuilder desired and optionally the name of the
+ * provider desired.<br />
+ * <br />
+ * Once a <code>CertPathBuilder</code> object has been created, certification
+ * paths can be constructed by calling the {@link #build build} method and
+ * passing it an algorithm-specific set of parameters. If successful, the result
+ * (including the CertPath that was built) is returned in an object that
+ * implements the <code>CertPathBuilderResult</code> interface.<br />
+ * <br />
+ * <strong>Concurrent Access</strong><br />
+ * <br />
+ * The static methods of this class are guaranteed to be thread-safe. Multiple
+ * threads may concurrently invoke the static methods defined in this class with
+ * no ill effects.<br />
+ * <br />
+ * However, this is not true for the non-static methods defined by this class.
+ * Unless otherwise documented by a specific provider, threads that need to
+ * access a single <code>CertPathBuilder</code> instance concurrently should
+ * synchronize amongst themselves and provide the necessary locking. Multiple
+ * threads each manipulating a different <code>CertPathBuilder</code> instance
+ * need not synchronize.<br />
+ * <br />
+ */
+public class CertPathBuilder extends Object
+{
+ private CertPathBuilderSpi builderSpi;
+
+ private Provider provider;
+
+ private String algorithm;
+
+ /**
+ * Creates a CertPathBuilder object of the given algorithm, and encapsulates
+ * the given provider implementation (SPI object) in it.
+ *
+ * @param builderSpi
+ * the provider implementation
+ * @param provider
+ * the provider
+ * @param algorithm
+ * the algorithm name
+ */
+ protected CertPathBuilder(
+ CertPathBuilderSpi builderSpi,
+ Provider provider,
+ String algorithm)
+ {
+ this.builderSpi = builderSpi;
+ this.provider = provider;
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Returns a CertPathBuilder object that implements the specified algorithm.<br />
+ * <br />
+ * If the default provider package provides an implementation of the
+ * specified CertPathBuilder algorithm, an instance of CertPathBuilder
+ * containing that implementation is returned. If the requested algorithm is
+ * not available in the default package, other packages are searched.<br />
+ * <br />
+ *
+ * @param algorithm
+ * the name of the requested CertPathBuilder algorithm
+ *
+ * @return a CertPathBuilder object that implements the specified algorithm
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested algorithm is not available in the default
+ * provider package or any of the other provider packages
+ * that were searched
+ */
+ public static CertPathBuilder getInstance(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ try
+ {
+ CertUtil.Implementation imp = CertUtil.getImplementation(
+ "CertPathBuilder", algorithm, (String)null);
+ if (imp != null)
+ {
+ return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(),
+ imp.getProvider(), algorithm);
+ }
+ }
+ catch (NoSuchProviderException ex)
+ {
+ }
+ throw new NoSuchAlgorithmException("can't find type " + algorithm);
+ }
+
+ /**
+ * Returns a CertPathBuilder object that implements the specified algorithm,
+ * as supplied by the specified provider.
+ *
+ * @param algorithm
+ * the name of the requested CertPathBuilder algorithm
+ * @param provider
+ * the name of the provider
+ *
+ * @return a CertPathBuilder object that implements the specified algorithm,
+ * as supplied by the specified provider
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested algorithm is not available from the
+ * specified provider
+ * @exception NoSuchProviderException
+ * if the provider has not been configured
+ * @exception IllegalArgumentException
+ * if the provider is null
+ */
+ public static CertPathBuilder getInstance(String algorithm, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ throw new IllegalArgumentException("provider must be non-null");
+ }
+ CertUtil.Implementation imp = CertUtil.getImplementation(
+ "CertPathBuilder", algorithm, provider);
+
+ if (imp != null)
+ {
+ return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(), imp
+ .getProvider(), algorithm);
+ }
+ throw new NoSuchAlgorithmException("can't find type " + algorithm);
+ }
+
+ /**
+ * Returns a CertPathBuilder object that implements the specified algorithm,
+ * as supplied by the specified provider. Note: the provider doesn't have to
+ * be registered.
+ *
+ * @param algorithm
+ * the name of the requested CertPathBuilder algorithm
+ * @param provider
+ * the provider
+ * @return a CertPathBuilder object that implements the specified algorithm,
+ * as supplied by the specified provider
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested algorithm is not available from the
+ * specified provider
+ * @exception IllegalArgumentException
+ * if the provider is null.
+ */
+ public static CertPathBuilder getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException
+ {
+ if (provider == null)
+ {
+ throw new IllegalArgumentException("provider must be non-null");
+ }
+ CertUtil.Implementation imp = CertUtil.getImplementation(
+ "CertPathBuilder", algorithm, provider);
+
+ if (imp != null)
+ {
+ return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(),
+ provider, algorithm);
+ }
+ throw new NoSuchAlgorithmException("can't find type " + algorithm);
+ }
+
+ /**
+ * Returns the provider of this <code>CertPathBuilder</code>.
+ *
+ * @return the provider of this <code>CertPathBuilder</code>
+ */
+ public final Provider getProvider()
+ {
+ return provider;
+ }
+
+ /**
+ * Returns the name of the algorithm of this <code>CertPathBuilder</code>.
+ *
+ * @return the name of the algorithm of this <code>CertPathBuilder</code>
+ */
+ public final String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * Attempts to build a certification path using the specified algorithm
+ * parameter set.
+ *
+ * @param params
+ * the algorithm parameters
+ *
+ * @return the result of the build algorithm
+ *
+ * @exception CertPathBuilderException
+ * if the builder is unable to construct a certification path
+ * that satisfies the specified parameters
+ * @exception InvalidAlgorithmParameterException
+ * if the specified parameters * are inappropriate for this
+ * <code>CertPathBuilder</code>
+ */
+ public final CertPathBuilderResult build(CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException
+ {
+ return builderSpi.engineBuild(params);
+ }
+
+ /**
+ * Returns the default <code>CertPathBuilder</code> type as specified in
+ * the Java security properties file, or the string &quot;PKIX&quot; if no
+ * such property exists. The Java security properties file is located in the
+ * file named &lt;JAVA_HOME&gt;/lib/security/java.security, where
+ * &lt;JAVA_HOME&gt; refers to the directory where the SDK was installed.<br />
+ * <br />
+ * The default <code>CertPathBuilder</code> type can be used by
+ * applications that do not want to use a hard-coded type when calling one
+ * of the <code>getInstance</code> methods, and want to provide a default
+ * type in case a user does not specify its own.<br />
+ * <br />
+ * The default <code>CertPathBuilder</code> type can be changed by setting
+ * the value of the "certpathbuilder.type" security property (in the Java
+ * security properties file) to the desired type.
+ *
+ * @return the default <code>CertPathBuilder</code> type as specified in
+ * the Java security properties file, or the string &quot;PKIX&quot;
+ * if no such property exists.
+ */
+ public static final String getDefaultType()
+ {
+ String defaulttype = null;
+ defaulttype = Security.getProperty("certpathbuilder.type");
+
+ if (defaulttype == null || defaulttype.length() <= 0)
+ {
+ return "PKIX";
+ }
+ else
+ {
+ return defaulttype;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java
new file mode 100644
index 000000000..1dce8758f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java
@@ -0,0 +1,182 @@
+package org.spongycastle.jce.cert;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.security.GeneralSecurityException;
+
+/**
+ * An exception indicating one of a variety of problems encountered
+ * when building a certification path with a
+ * <code>CertPathBuilder</code>.<br />
+ * <br />
+ * A <code>CertPathBuilderException</code> provides support for
+ * wrapping exceptions. The {@link #getCause() getCause} method
+ * returns the throwable, if any, that caused this exception to be
+ * thrown.<br />
+ * <br />
+ * <strong>Concurrent Access</strong><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are
+ * not thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathBuilder
+ **/
+public class CertPathBuilderException extends GeneralSecurityException
+{
+ private Throwable cause;
+
+ /**
+ * Creates a <code>CertPathBuilderException</code> with <code>null</code>
+ * as its detail message.
+ */
+ public CertPathBuilderException()
+ {
+ }
+
+ /**
+ * Creates a <code>CertPathBuilderException</code> with the given detail
+ * message. The detail message is a <code>String</code> that describes
+ * this particular exception in more detail.
+ *
+ * @param msg
+ * the detail message
+ */
+ public CertPathBuilderException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Creates a <code>CertPathBuilderException</code> that wraps the
+ * specified throwable. This allows any exception to be converted into a
+ * <code>CertPathBuilderException</code>, while retaining information
+ * about the wrapped exception, which may be useful for debugging. The
+ * detail message is set to
+ * <code>(cause==null ? null : cause.toString())</code> (which typically
+ * contains the class and detail message of cause).
+ *
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is permitted, and
+ * indicates that the cause is nonexistent or unknown.)
+ */
+ public CertPathBuilderException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ /**
+ * Creates a <code>CertPathBuilderException</code> with the specified
+ * detail message and cause.
+ *
+ * @param msg
+ * the detail message
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is permitted, and
+ * indicates that the cause is nonexistent or unknown.)
+ */
+ public CertPathBuilderException(Throwable cause)
+ {
+ this.cause = cause;
+ }
+
+ /**
+ * Returns the internal (wrapped) cause, or null if the cause is nonexistent
+ * or unknown.
+ *
+ * @return the cause of this throwable or <code>null</code> if the cause
+ * is nonexistent or unknown.
+ */
+ public Throwable getCause()
+ {
+ return cause;
+ }
+
+ /**
+ * Returns the detail message for this CertPathBuilderException.
+ *
+ * @return the detail message, or <code>null</code> if neither the message
+ * nor internal cause were specified
+ */
+ public String getMessage()
+ {
+ String message = super.getMessage();
+
+ if (message == null && cause == null)
+ {
+ return null;
+ }
+
+ if (cause != null)
+ {
+ return cause.getMessage();
+ }
+
+ return message;
+ }
+
+ /**
+ * Returns a string describing this exception, including a description of
+ * the internal (wrapped) cause if there is one.
+ *
+ * @return a string representation of this
+ * <code>CertPathBuilderException</code>
+ */
+ public String toString()
+ {
+ String message = getMessage();
+ if (message == null)
+ {
+ return "";
+ }
+
+ return message;
+ }
+
+ /**
+ * Prints a stack trace to <code>System.err</code>, including the
+ * backtrace of the cause, if any.
+ */
+ public void printStackTrace()
+ {
+ printStackTrace(System.err);
+ }
+
+ /**
+ * Prints a stack trace to a <code>PrintStream</code>, including the
+ * backtrace of the cause, if any.
+ *
+ * @param ps
+ * the <code>PrintStream</code> to use for output
+ */
+ public void printStackTrace(PrintStream ps)
+ {
+ super.printStackTrace(ps);
+ if (getCause() != null)
+ {
+ getCause().printStackTrace(ps);
+ }
+ }
+
+ /**
+ * Prints a stack trace to a <code>PrintWriter</code>, including the
+ * backtrace of the cause, if any.
+ *
+ * @param ps
+ * the <code>PrintWriter</code> to use for output
+ */
+ public void printStackTrace(PrintWriter pw)
+ {
+ super.printStackTrace(pw);
+ if (getCause() != null)
+ {
+ getCause().printStackTrace(pw);
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java
new file mode 100644
index 000000000..a1518cba4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java
@@ -0,0 +1,38 @@
+package org.spongycastle.jce.cert;
+
+/**
+ * A specification of the result of a certification path builder algorithm.
+ * All results returned by the {@link CertPathBuilder#build CertPathBuilder.build} method
+ * must implement this interface.<br />
+ * <br />
+ * At a minimum, a CertPathBuilderResult contains the CertPath built by the
+ * CertPathBuilder instance. Implementations of this interface may add methods
+ * to return implementation or algorithm specific information, such as
+ * debugging information or certification path validation results.<br />
+ * <br />
+ * <strong>Concurrent Access</strong><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this interface are not
+ * thread-safe. Multiple threads that need to access a single object
+ * concurrently should synchronize amongst themselves and provide the
+ * necessary locking. Multiple threads each manipulating separate objects
+ * need not synchronize.
+ **/
+public interface CertPathBuilderResult extends Cloneable
+{
+ /**
+ * Returns the built certification path.
+ *
+ * @return the certification path (never <code>null</code>)
+ */
+ public CertPath getCertPath();
+
+ /**
+ * Makes a copy of this <code>CertPathBuilderResult</code>.
+ * Changes to the copy will not affect the original and vice
+ * versa.
+ *
+ * @return a copy of this CertPathBuilderResult
+ */
+ public Object clone();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java
new file mode 100644
index 000000000..bb08d99a4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java
@@ -0,0 +1,50 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ * The Service Provider Interface (SPI) for the CertPathBuilder
+ * class. All CertPathBuilder implementations must include a class
+ * (the SPI class) that extends this class (CertPathBuilderSpi) and
+ * implements all of its methods. In general, instances of this class
+ * should only be accessed through the CertPathBuilder class. For
+ * details, see the Java Cryptography Architecture.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Instances of this class need not be protected against concurrent
+ * access from multiple threads. Threads that need to access a single
+ * CertPathBuilderSpi instance concurrently should synchronize amongst
+ * themselves and provide the necessary locking before calling the
+ * wrapping CertPathBuilder object.<br />
+ * <br />
+ * However, implementations of CertPathBuilderSpi may still encounter
+ * concurrency issues, since multiple threads each manipulating a
+ * different CertPathBuilderSpi instance need not synchronize.
+ **/
+public abstract class CertPathBuilderSpi
+ extends Object
+{
+ /**
+ * The default constructor.
+ */
+ public CertPathBuilderSpi() {}
+
+ /**
+ * Attempts to build a certification path using the specified
+ * algorithm parameter set.
+ *
+ * @param params the algorithm parameters
+ *
+ * @return the result of the build algorithm
+ *
+ * @exception CertPathBuilderException if the builder is unable
+ * to construct a certification path that satisfies the
+ * specified
+ * @exception parametersInvalidAlgorithmParameterException if the
+ * specified parameters are inappropriate for this CertPathBuilder
+ */
+ public abstract CertPathBuilderResult engineBuild(CertPathParameters params)
+ throws CertPathBuilderException,
+ InvalidAlgorithmParameterException;
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java
new file mode 100644
index 000000000..96978bd75
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java
@@ -0,0 +1,18 @@
+package org.spongycastle.jce.cert;
+
+/**
+ * A specification of certification path algorithm parameters. The purpose
+ * of this interface is to group (and provide type safety for) all CertPath
+ * parameter specifications. All <code>CertPath</code> parameter specifications must
+ * implement this interface.
+ **/
+public interface CertPathParameters extends Cloneable
+{
+ /**
+ * Makes a copy of this <code>CertPathParameters</code>. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this <code>CertPathParameters</code>
+ **/
+ public Object clone();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java
new file mode 100644
index 000000000..d2e599312
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java
@@ -0,0 +1,276 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+/**
+ * A class for validating certification paths (also known as certificate
+ * chains).<br />
+ * <br />
+ * This class uses a provider-based architecture, as described in the Java
+ * Cryptography Architecture. To create a <code>CertPathValidator</code>,
+ * call one of the static <code>getInstance</code> methods, passing in the
+ * algorithm name of the <code>CertPathValidator</code> desired and
+ * optionally the name of the provider desired. <br />
+ * <br />
+ * Once a <code>CertPathValidator</code> object has been created, it can
+ * be used to validate certification paths by calling the {@link #validate
+ * validate} method and passing it the <code>CertPath</code> to be validated
+ * and an algorithm-specific set of parameters. If successful, the result is
+ * returned in an object that implements the
+ * <code>CertPathValidatorResult</code> interface.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * The static methods of this class are guaranteed to be thread-safe.
+ * Multiple threads may concurrently invoke the static methods defined in
+ * this class with no ill effects.<br />
+ * <br />
+ * However, this is not true for the non-static methods defined by this class.
+ * Unless otherwise documented by a specific provider, threads that need to
+ * access a single <code>CertPathValidator</code> instance concurrently should
+ * synchronize amongst themselves and provide the necessary locking. Multiple
+ * threads each manipulating a different <code>CertPathValidator</code>
+ * instance need not synchronize.<br />
+ * <br />
+ * @see CertPath
+ **/
+public class CertPathValidator extends Object
+{
+ private CertPathValidatorSpi validatorSpi;
+
+ private Provider provider;
+
+ private String algorithm;
+
+ /**
+ * Creates a <code>CertPathValidator</code> object of the given algorithm,
+ * and encapsulates the given provider implementation (SPI object) in it.
+ *
+ * @param validatorSpi
+ * the provider implementation
+ * @param provider
+ * the provider
+ * @param algorithm
+ * the algorithm name
+ */
+ protected CertPathValidator(
+ CertPathValidatorSpi validatorSpi,
+ Provider provider,
+ String algorithm)
+ {
+ this.validatorSpi = validatorSpi;
+ this.provider = provider;
+ this.algorithm = algorithm;
+ }
+
+ /**
+ * Returns a <code>CertPathValidator</code> object that implements the
+ * specified algorithm.<br />
+ * <br />
+ * If the default provider package provides an implementation of the
+ * specified <code>CertPathValidator</code> algorithm, an instance of
+ * <code>CertPathValidator</code> containing that implementation is
+ * returned. If the requested algorithm is not available in the default
+ * package, other packages are searched.
+ *
+ * @param algorithm
+ * the name of the requested <code>CertPathValidator</code>
+ * algorithm
+ *
+ * @return a <code>CertPathValidator</code> object that implements the
+ * specified algorithm
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested algorithm is not available in the default
+ * provider package or any of the other provider packages
+ * that were searched
+ */
+ public static CertPathValidator getInstance(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ try
+ {
+ CertUtil.Implementation imp = CertUtil.getImplementation(
+ "CertPathValidator", algorithm, (String)null);
+ if (imp != null)
+ {
+ return new CertPathValidator((CertPathValidatorSpi)imp
+ .getEngine(), imp.getProvider(), algorithm);
+ }
+ }
+ catch (NoSuchProviderException ex)
+ {
+ }
+ throw new NoSuchAlgorithmException("can't find algorithm " + algorithm);
+ }
+
+ /**
+ * Returns a <code>CertPathValidator</code> object that implements the
+ * specified algorithm, as supplied by the specified provider.
+ *
+ * @param algorithm
+ * the name of the requested <code>CertPathValidator</code>
+ * algorithm
+ * @param provider
+ * the name of the provider
+ *
+ * @return a <code>CertPathValidator</code> object that implements the
+ * specified algorithm, as supplied by the specified provider
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested algorithm is not available from the
+ * specified provider
+ * @exception NoSuchProviderException
+ * if the provider has not been configured
+ * @exception IllegalArgumentException
+ * if the <code>provider</code> is null
+ */
+ public static CertPathValidator getInstance(String algorithm,
+ String provider) throws NoSuchAlgorithmException,
+ NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ throw new IllegalArgumentException("provider must be non-null");
+ }
+
+ CertUtil.Implementation imp = CertUtil.getImplementation(
+ "CertPathValidator", algorithm, provider);
+ if (imp != null)
+ {
+ return new CertPathValidator((CertPathValidatorSpi)imp.getEngine(),
+ imp.getProvider(), algorithm);
+ }
+ throw new NoSuchAlgorithmException("can't find algorithm " + algorithm);
+ }
+
+ /**
+ * Returns a <code>CertPathValidator</code> object that implements the
+ * specified algorithm, as supplied by the specified provider. Note: the
+ * <code>provider</code> doesn't have to be registered.
+ *
+ * @param algorithm
+ * the name of the requested <code>CertPathValidator</code>
+ * algorithm
+ * @param provider
+ * the provider
+ *
+ * @return a <code>CertPathValidator</code> object that implements the
+ * specified algorithm, as supplied by the specified provider
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested algorithm is not available from the
+ * specified provider
+ * @exception IllegalArgumentException
+ * if the <code>provider</code> is null
+ */
+ public static CertPathValidator getInstance(String algorithm,
+ Provider provider) throws NoSuchAlgorithmException
+ {
+ if (provider == null)
+ {
+ throw new IllegalArgumentException("provider must be non-null");
+ }
+
+ CertUtil.Implementation imp = CertUtil.getImplementation(
+ "CertPathValidator", algorithm, provider);
+ if (imp != null)
+ {
+ return new CertPathValidator((CertPathValidatorSpi)imp.getEngine(),
+ provider, algorithm);
+ }
+ throw new NoSuchAlgorithmException("can't find algorithm " + algorithm);
+ }
+
+ /**
+ * Returns the <code>Provider</code> of this
+ * <code>CertPathValidator</code>.
+ *
+ * @return the <code>Provider</code> of this
+ * <code>CertPathValidator</code>
+ */
+ public final Provider getProvider()
+ {
+ return provider;
+ }
+
+ /**
+ * Returns the algorithm name of this <code>CertPathValidator</code>.
+ *
+ * @return the algorithm name of this <code>CertPathValidator</code>
+ */
+ public final String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * Validates the specified certification path using the specified algorithm
+ * parameter set.<br />
+ * <br />
+ * The <code>CertPath</code> specified must be of a type that is supported
+ * by the validation algorithm, otherwise an
+ * <code>InvalidAlgorithmParameterException</code> will be thrown. For
+ * example, a <code>CertPathValidator</code> that implements the PKIX
+ * algorithm validates <code>CertPath</code> objects of type X.509.
+ *
+ * @param certPath
+ * the <code>CertPath</code> to be validated
+ * @param params
+ * the algorithm parameters
+ *
+ * @return the result of the validation algorithm
+ *
+ * @exception CertPathValidatorException
+ * if the <code>CertPath</code> does not validate
+ * @exception InvalidAlgorithmParameterException
+ * if the specified parameters or the type of the specified
+ * <code>CertPath</code> are inappropriate for this
+ * <code>CertPathValidator</code>
+ */
+ public final CertPathValidatorResult validate(CertPath certPath,
+ CertPathParameters params) throws CertPathValidatorException,
+ InvalidAlgorithmParameterException
+ {
+ return validatorSpi.engineValidate(certPath, params);
+ }
+
+ /**
+ * Returns the default <code>CertPathValidator</code> type as specified in
+ * the Java security properties file, or the string &quot;PKIX&quot; if no
+ * such property exists. The Java security properties file is located in the
+ * file named &lt;JAVA_HOME&gt;/lib/security/java.security, where
+ * &lt;JAVA_HOME&gt; refers to the directory where the SDK was installed.<br />
+ * <br />
+ * The default <code>CertPathValidator</code> type can be used by
+ * applications that do not want to use a hard-coded type when calling one
+ * of the <code>getInstance</code> methods, and want to provide a default
+ * type in case a user does not specify its own.<br />
+ * <br />
+ * The default <code>CertPathValidator</code> type can be changed by
+ * setting the value of the "certpathvalidator.type" security property (in
+ * the Java security properties file) to the desired type.
+ *
+ * @return the default <code>CertPathValidator</code> type as specified in
+ * the Java security properties file, or the string &quot;PKIX&quot;
+ * if no such property exists.
+ */
+ public static final String getDefaultType()
+ {
+ String defaulttype = null;
+ defaulttype = Security.getProperty("certpathvalidator.type");
+
+ if (defaulttype == null || defaulttype.length() <= 0)
+ {
+ return "PKIX";
+ }
+ else
+ {
+ return defaulttype;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java
new file mode 100644
index 000000000..bcd67a4a7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java
@@ -0,0 +1,271 @@
+package org.spongycastle.jce.cert;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.security.GeneralSecurityException;
+
+/**
+ * An exception indicating one of a variety of problems encountered when
+ * validating a certification path. <br />
+ * <br />
+ * A <code>CertPathValidatorException</code> provides support for wrapping
+ * exceptions. The {@link #getCause getCause} method returns the throwable,
+ * if any, that caused this exception to be thrown. <br />
+ * <br />
+ * A <code>CertPathValidatorException</code> may also include the
+ * certification path that was being validated when the exception was thrown
+ * and the index of the certificate in the certification path that caused the
+ * exception to be thrown. Use the {@link #getCertPath getCertPath} and
+ * {@link #getIndex getIndex} methods to retrieve this information.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathValidator
+ **/
+public class CertPathValidatorException extends GeneralSecurityException
+{
+ private Throwable cause;
+ private CertPath certPath;
+ private int index = -1;
+
+ /**
+ * Creates a <code>CertPathValidatorException</code> with no detail
+ * message.
+ */
+ public CertPathValidatorException()
+ {
+ super();
+ }
+
+ /**
+ * Creates a <code>CertPathValidatorException</code> with the given detail
+ * message. A detail message is a <code>String</code> that describes this
+ * particular exception.
+ *
+ * @param messag
+ * the detail message
+ */
+ public CertPathValidatorException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Creates a <code>CertPathValidatorException</code> with the specified
+ * detail message and cause.
+ *
+ * @param msg
+ * the detail message
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause getCause()} method). (A <code>null</code>
+ * value is permitted, and indicates that the cause is
+ * nonexistent or unknown.)
+ */
+ public CertPathValidatorException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ /**
+ * Creates a <code>CertPathValidatorException</code> with the specified
+ * detail message, cause, certification path, and index.
+ *
+ * @param msg
+ * the detail message (or <code>null</code> if none)
+ * @param cause
+ * the cause (or <code>null</code> if none)
+ * @param certPath
+ * the certification path that was in the process of being
+ * validated when the error was encountered
+ * @param index
+ * the index of the certificate in the certification path that
+ * caused the error (or -1 if not applicable). Note that the list
+ * of certificates in a <code>CertPath</code> is zero based.
+ *
+ * @exception IndexOutOfBoundsException
+ * if the index is out of range
+ * <code>(index < -1 || (certPath != null && index >=
+ * certPath.getCertificates().size())</code>
+ * @exception IllegalArgumentException
+ * if <code>certPath</code> is <code>null</code> and
+ * <code>index</code> is not -1
+ */
+ public CertPathValidatorException(
+ String message,
+ Throwable cause,
+ CertPath certPath,
+ int index)
+ {
+ super(message);
+
+ if (certPath == null && index != -1)
+ {
+ throw new IllegalArgumentException(
+ "certPath = null and index != -1");
+ }
+ if (index < -1
+ || (certPath != null && index >= certPath.getCertificates()
+ .size()))
+ {
+ throw new IndexOutOfBoundsException(
+ " index < -1 or out of bound of certPath.getCertificates()");
+ }
+
+ this.cause = cause;
+ this.certPath = certPath;
+ this.index = index;
+ }
+
+ /**
+ * Creates a <code>CertPathValidatorException</code> that wraps the
+ * specified throwable. This allows any exception to be converted into a
+ * <code>CertPathValidatorException</code>, while retaining information
+ * about the wrapped exception, which may be useful for debugging. The
+ * detail message is set to (<code>cause==null ? null : cause.toString()
+ * </code>)
+ * (which typically contains the class and detail message of cause).
+ *
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause getCause()} method). (A <code>null</code>
+ * value is permitted, and indicates that the cause is
+ * nonexistent or unknown.)
+ */
+ public CertPathValidatorException(Throwable cause)
+ {
+ this.cause = cause;
+ }
+
+ /**
+ * Returns the detail message for this
+ * <code>CertPathValidatorException</code>.
+ *
+ * @return the detail message, or <code>null</code> if neither the message
+ * nor cause were specified
+ */
+ public String getMessage()
+ {
+ String message = super.getMessage();
+
+ if (message != null)
+ {
+ return message;
+ }
+
+ if (cause != null)
+ {
+ return cause.getMessage();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the certification path that was being validated when the
+ * exception was thrown.
+ *
+ * @return the <code>CertPath</code> that was being validated when the
+ * exception was thrown (or <code>null</code> if not specified)
+ */
+ public CertPath getCertPath()
+ {
+ return certPath;
+ }
+
+ /**
+ * Returns the index of the certificate in the certification path that
+ * caused the exception to be thrown. Note that the list of certificates in
+ * a <code>CertPath</code> is zero based. If no index has been set, -1 is
+ * returned.
+ *
+ * @return the index that has been set, or -1 if none has been set
+ */
+ public int getIndex()
+ {
+ return index;
+ }
+
+ /**
+ * Returns the cause of this <code>CertPathValidatorException</code> or
+ * <code>null</code> if the cause is nonexistent or unknown.
+ *
+ * @return the cause of this throwable or <code>null</code> if the cause
+ * is nonexistent or unknown.
+ */
+ public Throwable getCause()
+ {
+ return cause;
+ }
+
+ /**
+ * Returns a string describing this exception, including a description of
+ * the internal (wrapped) cause if there is one.
+ *
+ * @return a string representation of this
+ * <code>CertPathValidatorException</code>
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ String s = getMessage();
+ if (s != null)
+ {
+ sb.append(s);
+ }
+ if (getIndex() >= 0)
+ {
+ sb.append("index in certpath: ").append(getIndex()).append('\n');
+ sb.append(getCertPath());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Prints a stack trace to <code>System.err</code>, including the
+ * backtrace of the cause, if any.
+ */
+ public void printStackTrace()
+ {
+ printStackTrace(System.err);
+ }
+
+ /**
+ * Prints a stack trace to a <code>PrintStream</code>, including the
+ * backtrace of the cause, if any.
+ *
+ * @param ps
+ * the <code>PrintStream</code> to use for output
+ */
+ public void printStackTrace(PrintStream ps)
+ {
+ super.printStackTrace(ps);
+ if (getCause() != null)
+ {
+ getCause().printStackTrace(ps);
+ }
+ }
+
+ /**
+ * Prints a stack trace to a <code>PrintWriter</code>, including the
+ * backtrace of the cause, if any.
+ *
+ * @param pw
+ * the <code>PrintWriter</code> to use for output
+ */
+ public void printStackTrace(PrintWriter pw)
+ {
+ super.printStackTrace(pw);
+ if (getCause() != null)
+ {
+ getCause().printStackTrace(pw);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java
new file mode 100644
index 000000000..e31b23f29
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java
@@ -0,0 +1,22 @@
+package org.spongycastle.jce.cert;
+
+/**
+ * A specification of the result of a certification path validator algorithm.<br />
+ * <br />
+ * The purpose of this interface is to group (and provide type safety
+ * for) all certification path validator results. All results returned
+ * by the {@link CertPathValidator#validate CertPathValidator.validate}
+ * method must implement this interface.
+ *
+ * @see CertPathValidator
+ **/
+public interface CertPathValidatorResult extends Cloneable
+{
+ /**
+ * Makes a copy of this <code>CertPathValidatorResult</code>. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this <code>CertPathValidatorResult</code>
+ */
+ public Object clone();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java
new file mode 100644
index 000000000..39f706d21
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java
@@ -0,0 +1,59 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ *
+ * The <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@link CertPathValidator CertPathValidator} class. All
+ * <code>CertPathValidator</code> implementations must include a class (the
+ * SPI class) that extends this class (<code>CertPathValidatorSpi</code>)
+ * and implements all of its methods. In general, instances of this class
+ * should only be accessed through the <code>CertPathValidator</code> class.
+ * For details, see the Java Cryptography Architecture.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Instances of this class need not be protected against concurrent
+ * access from multiple threads. Threads that need to access a single
+ * <code>CertPathValidatorSpi</code> instance concurrently should synchronize
+ * amongst themselves and provide the necessary locking before calling the
+ * wrapping <code>CertPathValidator</code> object.<br />
+ * <br />
+ * However, implementations of <code>CertPathValidatorSpi</code> may still
+ * encounter concurrency issues, since multiple threads each
+ * manipulating a different <code>CertPathValidatorSpi</code> instance need not
+ * synchronize.
+ **/
+public abstract class CertPathValidatorSpi extends Object
+{
+ /**
+ * The default constructor.
+ */
+ public CertPathValidatorSpi() {}
+
+ /**
+ * Validates the specified certification path using the specified
+ * algorithm parameter set.<br />
+ * <br />
+ * The <code>CertPath</code> specified must be of a type that is
+ * supported by the validation algorithm, otherwise an
+ * <code>InvalidAlgorithmParameterException</code> will be thrown. For
+ * example, a <code>CertPathValidator</code> that implements the PKIX
+ * algorithm validates <code>CertPath</code> objects of type X.509.
+ *
+ * @param certPath the <code>CertPath</code> to be validated
+ * @param params the algorithm parameters
+ *
+ * @return the result of the validation algorithm
+ *
+ * @exception CertPathValidatorException if the <code>CertPath</code>
+ * does not validate
+ * @exception InvalidAlgorithmParameterException if the specified
+ * parameters or the type of the specified <code>CertPath</code> are
+ * inappropriate for this <code>CertPathValidator</code>
+ */
+ public abstract CertPathValidatorResult engineValidate(CertPath certPath, CertPathParameters params)
+ throws CertPathValidatorException,
+ InvalidAlgorithmParameterException;
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java
new file mode 100644
index 000000000..2f2b0b468
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java
@@ -0,0 +1,41 @@
+package org.spongycastle.jce.cert;
+
+import java.security.cert.Certificate;
+
+/**
+ * A selector that defines a set of criteria for selecting
+ * <code>Certificate</code>s. Classes that implement this interface
+ * are often used to specify which <code>Certificate</code>s should
+ * be retrieved from a <code>CertStore</code>.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this interface are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see Certificate
+ * @see CertStore
+ * @see CertStore#getCertificates
+ */
+public interface CertSelector extends Cloneable
+{
+ /**
+ * Decides whether a <code>Certificate</code> should be selected.
+ *
+ * @param cert the <code>Certificate</code> to be checked
+ * @return <code>true</code> if the <code>Certificate</code>
+ * should be selected, <code>false</code> otherwise
+ */
+ public boolean match(Certificate cert);
+
+ /**
+ * Makes a copy of this <code>CertSelector</code>. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this <code>CertSelector</code>
+ */
+ public Object clone();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java
new file mode 100644
index 000000000..8a284262a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java
@@ -0,0 +1,382 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Collection;
+
+/**
+ * A class for retrieving <code>Certificate</code>s and <code>CRL</code>s
+ * from a repository.<br />
+ * <br />
+ * This class uses a provider-based architecture, as described in the
+ * Java Cryptography Architecture.
+ * To create a <code>CertStore</code>, call one of the static
+ * <code>getInstance</code> methods, passing in the type of
+ * <code>CertStore</code> desired, any applicable initialization parameters
+ * and optionally the name of the provider desired. <br />
+ * <br />
+ * Once the <code>CertStore</code> has been created, it can be used to
+ * retrieve <code>Certificate</code>s and <code>CRL</code>s by calling its
+ * {@link #getCertificates(CertSelector selector) getCertificates} and
+ * {@link #getCRLs(CRLSelector selector) getCRLs} methods.<br />
+ * <br />
+ * Unlike a {@link java.security.KeyStore KeyStore}, which provides access
+ * to a cache of private keys and trusted certificates, a
+ * <code>CertStore</code> is designed to provide access to a potentially
+ * vast repository of untrusted certificates and CRLs. For example, an LDAP
+ * implementation of <code>CertStore</code> provides access to certificates
+ * and CRLs stored in one or more directories using the LDAP protocol and the
+ * schema as defined in the RFC service attribute. See Appendix A in the
+ * Java Certification Path API Programmer's Guide for more information about
+ * standard <code>CertStore</code> types.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * All public methods of <code>CertStore</code> objects must be thread-safe.
+ * That is, multiple threads may concurrently invoke these methods on a
+ * single <code>CertStore</code> object (or more than one) with no
+ * ill effects. This allows a <code>CertPathBuilder</code> to search for a
+ * CRL while simultaneously searching for further certificates, for instance.<br />
+ * <br />
+ * The static methods of this class are also guaranteed to be thread-safe.
+ * Multiple threads may concurrently invoke the static methods defined in
+ * this class with no ill effects.<br />
+ * <br />
+ **/
+public class CertStore extends Object
+{
+ private CertStoreSpi storeSpi;
+
+ private Provider provider;
+
+ private String type;
+
+ private CertStoreParameters params;
+
+ /**
+ * Creates a <code>CertStore</code> object of the given type, and
+ * encapsulates the given provider implementation (SPI object) in it.
+ *
+ * @param storeSpi
+ * the provider implementation
+ * @param provider
+ * the provider
+ * @param type
+ * the type
+ * @param params
+ * the initialization parameters (may be <code>null</code>)
+ */
+ protected CertStore(
+ CertStoreSpi storeSpi,
+ Provider provider,
+ String type,
+ CertStoreParameters params)
+ {
+ this.storeSpi = storeSpi;
+ this.provider = provider;
+ this.type = type;
+ this.params = params;
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector. If no <code>Certificate</code>s match
+ * the selector, an empty <code>Collection</code> will be returned.<br />
+ * <br />
+ * For some <code>CertStore</code> types, the resulting
+ * <code>Collection</code> may not contain <b>all</b> of the
+ * <code>Certificate</code>s that match the selector. For instance, an
+ * LDAP <code>CertStore</code> may not search all entries in the
+ * directory. Instead, it may just search entries that are likely to contain
+ * the <code>Certificate</code>s it is looking for.<br />
+ * <br />
+ * Some <code>CertStore</code> implementations (especially LDAP
+ * <code>CertStore</code>s) may throw a <code>CertStoreException</code>
+ * unless a non-null <code>CertSelector</code> is provided that includes
+ * specific criteria that can be used to find the certificates. Issuer
+ * and/or subject names are especially useful criteria.
+ *
+ * @param selector
+ * A <code>CertSelector</code> used to select which
+ * <code>Certificate</code>s should be returned. Specify
+ * <code>null</code> to return all <code>Certificate</code>s
+ * (if supported).
+ *
+ * @return A <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector (never <code>null</code>)
+ * @exception CertStoreException
+ * if an exception occurs
+ */
+ public final Collection getCertificates(CertSelector selector)
+ throws CertStoreException
+ {
+ return storeSpi.engineGetCertificates(selector);
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>CRL</code>s that match
+ * the specified selector. If no <code>CRL</code>s match the selector, an
+ * empty <code>Collection</code> will be returned.<br />
+ * <br />
+ * For some <code>CertStore</code> types, the resulting
+ * <code>Collection</code> may not contain <b>all</b> of the
+ * <code>CRL</code>s that match the selector. For instance, an LDAP
+ * <code>CertStore</code> may not search all entries in the directory.
+ * Instead, it may just search entries that are likely to contain the
+ * <code>CRL</code>s it is looking for.<br />
+ * <br />
+ * Some <code>CertStore</code> implementations (especially LDAP
+ * <code>CertStore</code>s) may throw a <code>CertStoreException</code>
+ * unless a non-null <code>CRLSelector</code> is provided that includes
+ * specific criteria that can be used to find the CRLs. Issuer names and/or
+ * the certificate to be checked are especially useful.
+ *
+ * @param selector
+ * A <code>CRLSelector</code> used to select which
+ * <code>CRL</code>s should be returned. Specify
+ * <code>null</code> to return all <code>CRL</code>s (if
+ * supported).
+ *
+ * @return A <code>Collection</code> of <code>CRL</code>s that match
+ * the specified selector (never <code>null</code>)
+ *
+ * @exception CertStoreException
+ * if an exception occurs
+ */
+ public final Collection getCRLs(CRLSelector selector)
+ throws CertStoreException
+ {
+ return storeSpi.engineGetCRLs(selector);
+ }
+
+ /**
+ * Returns a <code>CertStore</code> object that implements the specified
+ * <code>CertStore</code> type and is initialized with the specified
+ * parameters.<br />
+ * <br />
+ * If the default provider package provides an implementation of the
+ * specified <code>CertStore</code> type, an instance of
+ * <code>CertStore</code> containing that implementation is returned. If
+ * the requested type is not available in the default package, other
+ * packages are searched.<br />
+ * <br />
+ * The <code>CertStore</code> that is returned is initialized with the
+ * specified <code>CertStoreParameters</code>. The type of parameters
+ * needed may vary between different types of <code>CertStore</code>s.
+ * Note that the specified <code>CertStoreParameters</code> object is
+ * cloned.
+ *
+ * @param type
+ * the name of the requested <code>CertStore</code> type
+ * @param params
+ * the initialization parameters (may be <code>null</code>)
+ *
+ * @return a <code>CertStore</code> object that implements the specified
+ * <code>CertStore</code> type
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested type is not available in the default
+ * provider package or any of the other provider packages
+ * that were searched
+ * @exception InvalidAlgorithmParameterException
+ * if the specified initialization parameters are
+ * inappropriate for this <code>CertStore</code>
+ */
+ public static CertStore getInstance(String type, CertStoreParameters params)
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException
+ {
+ try
+ {
+ CertUtil.Implementation imp = CertUtil.getImplementation(
+ "CertStore", type, (String)null,
+ new Class[] { CertStoreParameters.class },
+ new Object[] { params });
+ if (imp != null)
+ {
+ return new CertStore((CertStoreSpi)imp.getEngine(), imp
+ .getProvider(), type, params);
+ }
+ }
+ catch (NoSuchProviderException ex)
+ {
+ }
+ throw new NoSuchAlgorithmException("can't find type " + type);
+ }
+
+ /**
+ * Returns a <code>CertStore</code> object that implements the specified
+ * <code>CertStore</code> type, as supplied by the specified provider and
+ * initialized with the specified parameters.<br />
+ * <br />
+ * The <code>CertStore</code> that is returned is initialized with the
+ * specified <code>CertStoreParameters</code>. The type of parameters
+ * needed may vary between different types of <code>CertStore</code>s.
+ * Note that the specified <code>CertStoreParameters</code> object is
+ * cloned.
+ *
+ * @param type
+ * the requested <code>CertStore</code> type
+ * @param params
+ * the initialization parameters (may be <code>null</code>)
+ * @param provider
+ * the name of the provider
+ *
+ * @return a <code>CertStore</code> object that implements the specified
+ * type, as supplied by the specified provider
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested type is not available from the specified
+ * provider
+ * @exception InvalidAlgorithmParameterException
+ * if the specified initialization parameters are
+ * inappropriate for this <code>CertStore</code>
+ * @exception NoSuchProviderException
+ * if the provider has not been configured
+ * @exception IllegalArgumentException
+ * if the <code>provider</code> is null
+ */
+ public static CertStore getInstance(String type,
+ CertStoreParameters params, String provider)
+ throws InvalidAlgorithmParameterException,
+ NoSuchAlgorithmException, NoSuchProviderException,
+ IllegalArgumentException
+ {
+ if (provider == null)
+ {
+ throw new IllegalArgumentException("provider must be non-null");
+ }
+
+ CertUtil.Implementation imp = CertUtil.getImplementation("CertStore",
+ type, provider, new Class[] { CertStoreParameters.class },
+ new Object[] { params });
+ if (imp != null)
+ {
+ return new CertStore((CertStoreSpi)imp.getEngine(), imp
+ .getProvider(), type, params);
+ }
+ throw new NoSuchAlgorithmException("can't find type " + type);
+ }
+
+ /**
+ * Returns a <code>CertStore</code> object that implements the specified
+ * <code>CertStore</code> type, as supplied by the specified provider and
+ * initialized with the specified parameters. Note: the
+ * <code>provider</code> doesn't have to be registered.<br />
+ * <br />
+ * The <code>CertStore</code> that is returned is initialized with the
+ * specified <code>CertStoreParameters</code>. The type of parameters
+ * needed may vary between different types of <code>CertStore</code>s.
+ * Note that the specified <code>CertStoreParameters</code> object is
+ * cloned.
+ *
+ * @param type
+ * the requested <code>CertStore</code> type
+ * @param params
+ * the initialization parameters (may be <code>null</code>)
+ * @param provider
+ * the provider
+ *
+ * @return a <code>CertStore</code> object that implements the specified
+ * type, as supplied by the specified provider
+ *
+ * @exception NoSuchAlgorithmException
+ * if the requested type is not available from the specified
+ * provider
+ * @exception InvalidAlgorithmParameterException
+ * if the specified initialization parameters are
+ * inappropriate for this <code>CertStore</code>
+ * @exception IllegalArgumentException
+ * if the <code>provider</code> is null
+ */
+ public static CertStore getInstance(String type,
+ CertStoreParameters params, Provider provider)
+ throws NoSuchAlgorithmException,
+ InvalidAlgorithmParameterException, IllegalArgumentException
+ {
+ if (provider == null)
+ {
+ throw new IllegalArgumentException("provider must be non-null");
+ }
+ CertUtil.Implementation imp = CertUtil.getImplementation("CertStore",
+ type, provider, new Class[] { CertStoreParameters.class },
+ new Object[] { params });
+ if (imp != null)
+ {
+ return new CertStore((CertStoreSpi)imp.getEngine(), provider, type,
+ params);
+ }
+ throw new NoSuchAlgorithmException("can't find type " + type);
+ }
+
+ /**
+ * Returns the parameters used to initialize this <code>CertStore</code>.
+ * Note that the <code>CertStoreParameters</code> object is cloned before
+ * it is returned.
+ *
+ * @return the parameters used to initialize this <code>CertStore</code>
+ * (may be <code>null</code>)
+ */
+ public final CertStoreParameters getCertStoreParameters()
+ {
+ return params;
+ }
+
+ /**
+ * Returns the type of this <code>CertStore</code>.
+ *
+ * @return the type of this <code>CertStore</code>
+ */
+ public final String getType()
+ {
+ return type;
+ }
+
+ /**
+ * Returns the provider of this <code>CertStore</code>.
+ *
+ * @return the provider of this <code>CertStore</code>
+ */
+ public final Provider getProvider()
+ {
+ return provider;
+ }
+
+ /**
+ * Returns the default <code>CertStore</code> type as specified in the
+ * Java security properties file, or the string &quot;LDAP&quot; if no such
+ * property exists. The Java security properties file is located in the file
+ * named &lt;JAVA_HOME&gt;/lib/security/java.security, where
+ * &lt;JAVA_HOME&gt; refers to the directory where the SDK was installed.<br />
+ * <br />
+ * The default <code>CertStore</code> type can be used by applications
+ * that do not want to use a hard-coded type when calling one of the
+ * <code>getInstance</code> methods, and want to provide a default
+ * <code>CertStore</code> type in case a user does not specify its own.<br />
+ * <br />
+ * The default <code>CertStore</code> type can be changed by setting the
+ * value of the "certstore.type" security property (in the Java security
+ * properties file) to the desired type.
+ *
+ * @return the default <code>CertStore</code> type as specified in the
+ * Java security properties file, or the string &quot;LDAP&quot; if
+ * no such property exists.
+ */
+ public static final String getDefaultType()
+ {
+ String defaulttype = null;
+ defaulttype = Security.getProperty("certstore.type");
+
+ if (defaulttype == null || defaulttype.length() <= 0)
+ {
+ return "LDAP";
+ }
+ else
+ {
+ return defaulttype;
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java
new file mode 100644
index 000000000..56c9fcfd2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java
@@ -0,0 +1,187 @@
+package org.spongycastle.jce.cert;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.security.GeneralSecurityException;
+
+/**
+ * An exception indicating one of a variety of problems retrieving
+ * certificates and CRLs from a <code>CertStore</code>.<br />
+ * <br />
+ * A <code>CertStoreException</code> provides support for wrapping
+ * exceptions. The {@link #getCause getCause} method returns the throwable,
+ * if any, that caused this exception to be thrown.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertStore
+ **/
+public class CertStoreException extends GeneralSecurityException
+{
+ private Throwable cause;
+
+ /**
+ * Creates a <code>CertStoreException</code> with <code>null</code> as
+ * its detail message.
+ */
+ public CertStoreException()
+ {
+ super();
+ }
+
+ /**
+ * Creates a <code>CertStoreException</code> with the given detail
+ * message. A detail message is a <code>String</code> that describes this
+ * particular exception.
+ *
+ * @param messag
+ * the detail message
+ */
+ public CertStoreException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Creates a <code>CertStoreException</code> with the specified detail
+ * message and cause.
+ *
+ * @param messag
+ * the detail message
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause getCause()} method). (A <code>null</code>
+ * value is permitted, and indicates that the cause is
+ * nonexistent or unknown.)
+ */
+ public CertStoreException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ /**
+ * Creates a <code>CertStoreException</code> that wraps the specified
+ * throwable. This allows any exception to be converted into a
+ * <code>CertStoreException</code>, while retaining information about the
+ * cause, which may be useful for debugging. The detail message is set to (<code>cause==null ? null : cause.toString()</code>)
+ * (which typically contains the class and detail message of cause).
+ *
+ * @param cause
+ * the cause (which is saved for later retrieval by the
+ * {@link #getCause getCause()} method). (A <code>null</code>
+ * value is permitted, and indicates that the cause is
+ * nonexistent or unknown.)
+ */
+ public CertStoreException(Throwable cause)
+ {
+ this.cause = cause;
+ }
+
+ /**
+ * Returns the detail message for this <code>CertStoreException</code>.
+ *
+ * @return the detail message, or <code>null</code> if neither the message
+ * nor cause were specified
+ */
+ public String getMessage()
+ {
+ String message = super.getMessage();
+
+ if (message == null && cause == null)
+ {
+ return null;
+ }
+
+ StringBuffer s = new StringBuffer();
+ if (message != null)
+ {
+ s.append(message).append('\n');
+ }
+ if (cause != null)
+ {
+ s.append("Cause:\n").append(cause.getMessage());
+ }
+ return s.toString();
+ }
+
+ /**
+ * Returns the cause of this <code>CertStoreException</code> or
+ * <code>null</code> if the cause is nonexistent or unknown.
+ *
+ * @return the cause of this throwable or <code>null</code> if the cause
+ * is nonexistent or unknown.
+ */
+ public Throwable getCause()
+ {
+ return cause;
+ }
+
+ /**
+ * Returns a string describing this exception, including a description of
+ * the internal (wrapped) cause if there is one.
+ *
+ * @return a string representation of this <code>CertStoreException</code>
+ */
+ public String toString()
+ {
+ String message = getMessage();
+ if (message == null)
+ {
+ return "";
+ }
+
+ return message;
+ }
+
+ /**
+ * Prints a stack trace to <code>System.err</code>, including the
+ * backtrace of the cause, if any.
+ */
+ public void printStackTrace()
+ {
+ printStackTrace(System.err);
+ }
+
+ /**
+ * Prints a stack trace to a <code>PrintStream</code>, including the
+ * backtrace of the cause, if any.
+ *
+ * @param ps
+ * the <code>PrintStream</code> to use for output
+ */
+ public void printStackTrace(PrintStream ps)
+ {
+ super.printStackTrace(ps);
+ if (cause != null)
+ {
+ cause.printStackTrace(ps);
+ }
+ }
+
+ /**
+ * Prints a stack trace to a <code>PrintWriter</code>, including the
+ * backtrace of the cause, if any.
+ *
+ * @param pw
+ * the <code>PrintWriter</code> to use for output
+ */
+ public void printStackTrace(PrintWriter pw)
+ {
+ if (cause != null)
+ {
+ cause.printStackTrace(pw);
+ }
+ super.printStackTrace(pw);
+ if (cause != null)
+ {
+ cause.printStackTrace(pw);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java
new file mode 100644
index 000000000..0ec14ede3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java
@@ -0,0 +1,52 @@
+package org.spongycastle.jce.cert;
+
+/**
+ * A specification of <code>CertStore</code> parameters.<br />
+ * <br />
+ * The purpose of this interface is to group (and provide type safety for)
+ * all <code>CertStore</code> parameter specifications. All
+ * <code>CertStore</code> parameter specifications must implement this
+ * interface. <br />
+ * <br />
+ * Typically, a <code>CertStoreParameters</code> object is passed as a parameter
+ * to one of the {@link CertStore#getInstance CertStore.getInstance} methods.
+ * The <code>getInstance</code> method returns a <code>CertStore</code> that
+ * is used for retrieving <code>Certificate</code>s and <code>CRL</code>s. The
+ * <code>CertStore</code> that is returned is initialized with the specified
+ * parameters. The type of parameters needed may vary between different types
+ * of <code>CertStore</code>s.
+ *
+ * @see CertStore#getInstance
+ **/
+public interface CertStoreParameters extends Cloneable
+{
+ /**
+ * Makes a copy of this <code>CertStoreParameters</code>.<br />
+ * <br />
+ * The precise meaning of "copy" may depend on the class of
+ * the <code>CertStoreParameters</code> object. A typical implementation
+ * performs a "deep copy" of this object, but this is not an absolute
+ * requirement. Some implementations may perform a "shallow copy" of some
+ * or all of the fields of this object.<br />
+ * <br />
+ * Note that the <code>CertStore.getInstance</code> methods make a copy
+ * of the specified <code>CertStoreParameters</code>. A deep copy
+ * implementation of <code>clone</code> is safer and more robust, as it
+ * prevents the caller from corrupting a shared <code>CertStore</code> by
+ * subsequently modifying the contents of its initialization parameters.
+ * However, a shallow copy implementation of <code>clone</code> is more
+ * appropriate for applications that need to hold a reference to a
+ * parameter contained in the <code>CertStoreParameters</code>. For example,
+ * a shallow copy clone allows an application to release the resources of
+ * a particular <code>CertStore</code> initialization parameter immediately,
+ * rather than waiting for the garbage collection mechanism. This should
+ * be done with the utmost care, since the <code>CertStore</code> may still
+ * be in use by other threads.<br />
+ * <br />
+ * Each subclass should state the precise behavior of this method so
+ * that users and developers know what to expect.
+ *
+ * @return a copy of this <code>CertStoreParameters</code>
+ */
+ public Object clone();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java
new file mode 100644
index 000000000..fd9fe6a36
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java
@@ -0,0 +1,104 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.util.Collection;
+
+/**
+ * The <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@link CertStore CertStore} class. All <code>CertStore</code>
+ * implementations must include a class (the SPI class) that extends
+ * this class (<code>CertStoreSpi</code>), provides a constructor with
+ * a single argument of type <code>CertStoreParameters</code>, and implements
+ * all of its methods. In general, instances of this class should only be
+ * accessed through the <code>CertStore</code> class.
+ * For details, see the Java Cryptography Architecture.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * The public methods of all <code>CertStoreSpi</code> objects must be
+ * thread-safe. That is, multiple threads may concurrently invoke these
+ * methods on a single <code>CertStoreSpi</code> object (or more than one)
+ * with no ill effects. This allows a <code>CertPathBuilder</code> to search
+ * for a CRL while simultaneously searching for further certificates, for
+ * instance.<br />
+ * <br />
+ * Simple <code>CertStoreSpi</code> implementations will probably ensure
+ * thread safety by adding a <code>synchronized</code> keyword to their
+ * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods.
+ * More sophisticated ones may allow truly concurrent access.
+ **/
+public abstract class CertStoreSpi
+ extends Object
+{
+
+ /**
+ * The sole constructor.
+ *
+ * @param params the initialization parameters (may be <code>null</code>)
+ * @exception InvalidAlgorithmParameterException if the initialization
+ * parameters are inappropriate for this <code>CertStoreSpi</code>
+ */
+ public CertStoreSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException {}
+
+ /**
+ * Returns a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector. If no <code>Certificate</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.<br />
+ * <br />
+ * For some <code>CertStore</code> types, the resulting
+ * <code>Collection</code> may not contain <b>all</b> of the
+ * <code>Certificate</code>s that match the selector. For instance,
+ * an LDAP <code>CertStore</code> may not search all entries in the
+ * directory. Instead, it may just search entries that are likely to
+ * contain the <code>Certificate</code>s it is looking for.<br />
+ * <br />
+ * Some <code>CertStore</code> implementations (especially LDAP
+ * <code>CertStore</code>s) may throw a <code>CertStoreException</code>
+ * unless a non-null <code>CertSelector</code> is provided that includes
+ * specific criteria that can be used to find the certificates. Issuer
+ * and/or subject names are especially useful criteria.
+ *
+ * @param selector A <code>CertSelector</code> used to select which
+ * <code>Certificate</code>s should be returned. Specify <code>null</code>
+ * to return all <code>Certificate</code>s (if supported).
+ *
+ * @return A <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector (never <code>null</code>)
+ *
+ * @exception CertStoreException if an exception occurs
+ */
+ public abstract Collection engineGetCertificates(CertSelector selector)
+ throws CertStoreException;
+
+ /**
+ * Returns a <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector. If no <code>CRL</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.<br />
+ * <br />
+ * For some <code>CertStore</code> types, the resulting
+ * <code>Collection</code> may not contain <b>all</b> of the
+ * <code>CRL</code>s that match the selector. For instance,
+ * an LDAP <code>CertStore</code> may not search all entries in the
+ * directory. Instead, it may just search entries that are likely to
+ * contain the <code>CRL</code>s it is looking for. <br />
+ * <br />
+ * Some <code>CertStore</code> implementations (especially LDAP
+ * <code>CertStore</code>s) may throw a <code>CertStoreException</code>
+ * unless a non-null <code>CRLSelector</code> is provided that includes
+ * specific criteria that can be used to find the CRLs. Issuer names
+ * and/or the certificate to be checked are especially useful.
+ *
+ * @param selector A <code>CRLSelector</code> used to select which
+ * <code>CRL</code>s should be returned. Specify <code>null</code>
+ * to return all <code>CRL</code>s (if supported).
+ *
+ * @return A <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector (never <code>null</code>)
+ *
+ * @exception CertStoreException if an exception occurs
+ */
+ public abstract Collection engineGetCRLs(CRLSelector selector)
+ throws CertStoreException;
+}
+
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java
new file mode 100644
index 000000000..60c5e8b08
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java
@@ -0,0 +1,556 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.OIDTokenizer;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.util.Strings;
+
+class CertUtil
+{
+ static class Implementation
+ {
+ Object engine;
+ Provider provider;
+
+ Implementation(
+ Object engine,
+ Provider provider)
+ {
+ this.engine = engine;
+ this.provider = provider;
+ }
+
+ Object getEngine()
+ {
+ return engine;
+ }
+
+ Provider getProvider()
+ {
+ return provider;
+ }
+ }
+
+ /**
+ * see if we can find an algorithm (or its alias and what it represents) in
+ * the property table for the given provider.
+ *
+ * @return null if no algorithm found, an Implementation if it is.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm,
+ Provider prov)
+ {
+ if (prov == null)
+ {
+ Provider[] provider = Security.getProviders();
+
+ //
+ // search every provider looking for the algorithm we want.
+ //
+ for (int i = 0; i != provider.length; i++)
+ {
+ Implementation imp = getImplementation(baseName, algorithm, provider[i]);
+ if (imp != null)
+ {
+ return imp;
+ }
+ }
+
+ return null;
+ }
+
+ String alias;
+
+ while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null)
+ {
+ algorithm = alias;
+ }
+
+ String className = prov.getProperty(baseName + "." + algorithm);
+
+ if (className != null)
+ {
+ try
+ {
+ return new Implementation(Class.forName(className).newInstance(), prov);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but no class found!");
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but class inaccessible: " + e.toString());
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * return an implementation for a given algorithm/provider.
+ * If the provider is null, we grab the first avalaible who has the required algorithm.
+ *
+ * @return null if no algorithm found, an Implementation if it is.
+ * @exception NoSuchProviderException if a provider is specified and not found.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm,
+ String provider)
+ throws NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ Provider[] prov = Security.getProviders();
+
+ //
+ // search every provider looking for the algorithm we want.
+ //
+ for (int i = 0; i != prov.length; i++)
+ {
+ Implementation imp = getImplementation(baseName, algorithm, prov[i]);
+ if (imp != null)
+ {
+ return imp;
+ }
+ }
+ }
+ else
+ {
+ Provider prov = Security.getProvider(provider);
+
+ if (prov == null)
+ {
+ throw new NoSuchProviderException("Provider " + provider + " not found");
+ }
+
+ return getImplementation(baseName, algorithm, prov);
+ }
+
+ return null;
+ }
+
+ /**
+ * see if we can find an algorithm (or its alias and what it represents) in
+ * the property table for the given provider.
+ *
+ * @return null if no algorithm found, an Implementation if it is.
+ */
+ static Implementation getImplementation(String baseName, String algorithm,
+ Provider prov, Class[] ctorparamtype, Object[] ctorparam)
+ throws InvalidAlgorithmParameterException
+ {
+ String alias;
+
+ while ((alias = prov.getProperty("Alg.Alias." + baseName + "."
+ + algorithm)) != null)
+ {
+ algorithm = alias;
+ }
+
+ String className = prov.getProperty(baseName + "." + algorithm);
+
+ if (className != null)
+ {
+ try
+ {
+ return new Implementation(Class.forName(className)
+ .getConstructor(ctorparamtype).newInstance(ctorparam),
+ prov);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalStateException("algorithm " + algorithm
+ + " in provider " + prov.getName()
+ + " but no class found!");
+ }
+ catch (Exception e)
+ {
+ if (e instanceof InvalidAlgorithmParameterException)
+ {
+ throw (InvalidAlgorithmParameterException)e;
+ }
+
+ throw new IllegalStateException("algorithm " + algorithm
+ + " in provider " + prov.getName()
+ + " but class inaccessible!");
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * return an implementation for a given algorithm/provider. If the provider
+ * is null, we grab the first avalaible who has the required algorithm.
+ *
+ * @return null if no algorithm found, an Implementation if it is.
+ *
+ * @exception NoSuchProviderException
+ * if a provider is specified and not found.
+ */
+ static Implementation getImplementation(String baseName, String algorithm,
+ String provider, Class[] ctorparamtype, Object[] ctorparam)
+ throws NoSuchProviderException, InvalidAlgorithmParameterException
+ {
+ if (provider == null)
+ {
+ Provider[] prov = Security.getProviders();
+
+ //
+ // search every provider looking for the algorithm we want.
+ //
+ for (int i = 0; i != prov.length; i++)
+ {
+ Implementation imp = getImplementation(baseName, algorithm,
+ prov[i], ctorparamtype, ctorparam);
+ if (imp != null)
+ {
+ return imp;
+ }
+ }
+ }
+ else
+ {
+ Provider prov = Security.getProvider(provider);
+
+ if (prov == null)
+ {
+ throw new NoSuchProviderException("Provider " + provider
+ + " not found");
+ }
+
+ return getImplementation(baseName, algorithm, prov, ctorparamtype,
+ ctorparam);
+ }
+
+ return null;
+ }
+
+ static byte[] parseGeneralName(int type, String data) throws IOException
+ {
+ byte[] encoded = null;
+
+ switch (type)
+ {
+ case 0:
+ throw new IOException(
+ "unable to parse OtherName String representation");
+ case 1:
+ encoded = parseRfc822(data.trim());
+ break;
+ case 2:
+ encoded = parseDNSName(data.trim());
+ break;
+ case 3:
+ throw new IOException(
+ "unable to parse ORAddress String representation");
+ case 4:
+ encoded = parseX509Name(data.trim());
+ break;
+ case 5:
+ throw new IOException(
+ "unable to parse EDIPartyName String representation");
+ case 6:
+ encoded = parseURI(data.trim());
+ break;
+ case 7:
+ encoded = parseIP(data.trim());
+ break;
+ case 8:
+ encoded = parseOID(data.trim());
+ break;
+ default:
+ throw new IOException(
+ "unable to parse unkown type String representation");
+ }
+ return encoded;
+ }
+
+ /**
+ * Check the format of an OID.<br />
+ * Throw an IOException if the first component is not 0, 1 or 2 or the
+ * second component is greater than 39.<br />
+ * <br />
+ * User {@link org.spongycastle.asn1.OIDTokenizer OIDTokenizer}
+ *
+ * @param the
+ * OID to be checked.
+ *
+ * @exception IOException
+ * if the first component is not 0, 1 or 2 or the second
+ * component is greater than 39.
+ */
+ static byte[] parseOID(String oid) throws IOException
+ {
+ OIDTokenizer tokenizer = new OIDTokenizer(oid);
+ String token;
+ if (!tokenizer.hasMoreTokens())
+ {
+ throw new IOException("OID contains no tokens");
+ }
+ token = tokenizer.nextToken();
+ if (token == null)
+ {
+ throw new IOException("OID contains no tokens");
+ }
+ try
+ {
+ int test = (Integer.valueOf(token)).intValue();
+ if (test < 0 || test > 2)
+ {
+ throw new IOException("first token is not >= 0 and <=2");
+ }
+ if (!tokenizer.hasMoreTokens())
+ {
+ throw new IOException("OID contains only one token");
+ }
+ token = tokenizer.nextToken();
+ if (token == null)
+ {
+ throw new IOException("OID contains only one token");
+ }
+ test = (Integer.valueOf(token)).intValue();
+ if (test < 0 || test > 39)
+ {
+ throw new IOException("secon token is not >= 0 and <=39");
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new IOException("token: " + token + ": " + ex.toString());
+ }
+ ASN1Object derData = new ASN1ObjectIdentifier(oid);
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DEROutputStream derOutStream = new DEROutputStream(outStream);
+ derOutStream.writeObject(derData);
+ derOutStream.close();
+ return outStream.toByteArray();
+ }
+
+ /**
+ * Parse the given IPv4 or IPv6 into DER encoded byte array representation.
+ *
+ * @param the
+ * IP in well known String format
+ *
+ * @return the IP as byte array
+ *
+ * @exception IOException
+ * if the String could not be parsed
+ */
+ private static byte[] parseIP(String data) throws IOException
+ {
+ byte[] encoded = parseIPv4(data);
+
+ if (encoded == null)
+ {
+ encoded = parseIPv6(data);
+ }
+
+ if (encoded == null)
+ {
+ throw new IOException(
+ "unable to parse IP to DER encoded byte array");
+ }
+
+ return encoded;
+ }
+
+ /**
+ * Parse the given IPv4 into DER encoded byte array representation.
+ *
+ * @param the
+ * IP in well known String format
+ *
+ * @return the IP as byte array or <code>null</code> if not parseable
+ */
+ private static byte[] parseIPv4(String data)
+ {
+ if (data.length() == 0)
+ {
+ return null;
+ }
+
+ int octet;
+ int octets = 0;
+ byte[] dst = new byte[4];
+
+ int pos = 0;
+ int start = 0;
+ while (start < data.length()
+ && (pos = data.indexOf('.', start)) > start && pos - start > 3)
+ {
+ try
+ {
+ octet = (Integer.valueOf(data.substring(start, pos - start)))
+ .intValue();
+ }
+ catch (NumberFormatException ex)
+ {
+ return null;
+ }
+ if (octet < 0 || octet > 255)
+ {
+ return null;
+ }
+ dst[octets++] = (byte)(octet & 0xff);
+
+ start = pos + 1;
+ }
+
+ if (octets < 4)
+ {
+ return null;
+ }
+
+ return dst;
+ }
+
+ /**
+ * Parse the given IPv6 into DER encoded byte array representation.<br />
+ * <br />
+ * <b>TODO: implement this</b>
+ *
+ * @param the
+ * IP in well known String format
+ *
+ * @return the IP as byte array or <code>null</code> if not parseable
+ */
+ private static byte[] parseIPv6(String data)
+ {
+ return null;
+ }
+
+ /**
+ * Parse the given URI into DER encoded byte array representation.
+ *
+ * @param the
+ * URI in well known String format
+ *
+ * @return the URI as byte array
+ *
+ * @exception IOException
+ * if the String could not be parsed
+ */
+ private static byte[] parseURI(String data) throws IOException
+ {
+ // TODO do parsing test
+ ASN1Object derData = new DERIA5String(data);
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DEROutputStream derOutStream = new DEROutputStream(outStream);
+ derOutStream.writeObject(derData);
+ derOutStream.close();
+ return outStream.toByteArray();
+ }
+
+ /**
+ * Parse the given rfc822 addr-spec into DER encoded byte array
+ * representation.
+ *
+ * @param the
+ * rfc822 addr-spec in well known String format
+ *
+ * @return the rfc822 addr-spec as byte array
+ *
+ * @exception IOException
+ * if the String could not be parsed
+ */
+ private static byte[] parseRfc822(String data) throws IOException
+ {
+ int tmpInt = data.indexOf('@');
+ if (tmpInt < 0 || tmpInt >= data.length() - 1)
+ {
+ throw new IOException("wrong format of rfc822Name:" + data);
+ }
+ // TODO more test for illegal charateers
+ ASN1Object derData = new DERIA5String(data);
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DEROutputStream derOutStream = new DEROutputStream(outStream);
+ derOutStream.writeObject(derData);
+ derOutStream.close();
+ return outStream.toByteArray();
+ }
+
+ /**
+ * Parse the given DNS name into DER encoded byte array representation. The
+ * String must be in den preffered name syntax as defined in RFC 1034.
+ *
+ * @param the
+ * DNS name in well known String format
+ *
+ * @return the DNS name as byte array
+ *
+ * @exception IOException
+ * if the String could not be parsed
+ */
+ private static byte[] parseDNSName(String data) throws IOException
+ {
+ // TODO more test for illegal charateers
+ ASN1Object derData = new DERIA5String(data);
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DEROutputStream derOutStream = new DEROutputStream(outStream);
+ derOutStream.writeObject(derData);
+ derOutStream.close();
+ return outStream.toByteArray();
+ }
+
+ /**
+ * Parse the given X.509 name into DER encoded byte array representation.
+ *
+ * @param the
+ * X.509 name in well known String format
+ *
+ * @return the X.509 name as byte array
+ *
+ * @exception IOException
+ * if the String could not be parsed
+ */
+ private static byte[] parseX509Name(String data) throws IOException
+ {
+ // TODO more test for illegal charateers
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DEROutputStream derOutStream = new DEROutputStream(outStream);
+ derOutStream.writeObject(new X509Name(trimX509Name(data)));
+ derOutStream.close();
+ return outStream.toByteArray();
+ }
+
+ /**
+ * Returns the given name converted to upper case and all multi spaces squezed
+ * to one space.
+ **/
+ static String trimX509Name(String name)
+ {
+ String data = Strings.toUpperCase(name.trim());
+ int pos;
+ while ((pos = data.indexOf(" ")) >= 0)
+ {
+ data = data.substring(0, pos) + data.substring(pos + 1);
+ }
+ while ((pos = data.indexOf(" =")) >= 0)
+ {
+ data = data.substring(0, pos) + data.substring(pos + 1);
+ }
+ while ((pos = data.indexOf("= ")) >= 0)
+ {
+ data = data.substring(0, pos + 1) + data.substring(pos + 2);
+ }
+ return data;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java
new file mode 100644
index 000000000..a1ead1a63
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java
@@ -0,0 +1,183 @@
+package org.spongycastle.jce.cert;
+
+import java.io.InputStream;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ **/
+public class CertificateFactory
+{
+ private CertificateFactorySpi certFacSpi;
+ private Provider provider;
+ private String type;
+
+ protected CertificateFactory(
+ CertificateFactorySpi certFacSpi,
+ Provider provider,
+ String type)
+ {
+ this.certFacSpi = certFacSpi;
+ this.provider = provider;
+ this.type = type;
+ }
+
+ public final CRL generateCRL(InputStream inStream)
+ throws CRLException
+ {
+ return certFacSpi.engineGenerateCRL(inStream);
+ }
+
+ public final Collection generateCRLs(InputStream inStream)
+ throws CRLException
+ {
+ return certFacSpi.engineGenerateCRLs(inStream);
+ }
+
+ public final Certificate generateCertificate(InputStream inStream)
+ throws CertificateException
+ {
+ return certFacSpi.engineGenerateCertificate(inStream);
+ }
+
+ public final /*Sk13 Vector*/ Collection generateCertificates(InputStream inStream)
+ throws CertificateException
+ {
+ return certFacSpi.engineGenerateCertificates(inStream);
+ }
+
+ /**
+ * Returns an iteration of the <code>CertPath</code> encodings supported
+ * by this certificate factory, with the default encoding first. See
+ * Appendix A in the
+ * Java Certification Path API Programmer's Guide for information about
+ * standard encoding names and their formats.<br />
+ * <br />
+ * Attempts to modify the returned <code>Iterator</code> via its
+ * <code>remove</code> method result in an
+ * <code>UnsupportedOperationException</code>.
+ *
+ * @return an <code>Iterator</code> over the names of the supported
+ * <code>CertPath</code> encodings (as <code>String</code>s)
+ */
+ public final Iterator getCertPathEncodings()
+ {
+ return certFacSpi.engineGetCertPathEncodings();
+ }
+
+ /**
+ * Generates a <code>CertPath</code> object and initializes it with
+ * the data read from the <code>InputStream</code> inStream. The data
+ * is assumed to be in the default encoding. The name of the default
+ * encoding is the first element of the <code>Iterator</code> returned by
+ * the {@link #getCertPathEncodings getCertPathEncodings} method.
+ *
+ * @param inStream an <code>InputStream</code> containing the data
+ *
+ * @return a <code>CertPath</code> initialized with the data from the
+ * <code>InputStream</code>
+ *
+ * @exception CertificateException if an exception occurs while decoding
+ */
+ public final CertPath generateCertPath(InputStream inStream)
+ throws CertificateException
+ {
+ return certFacSpi.engineGenerateCertPath(inStream);
+ }
+
+ /**
+ * Generates a <code>CertPath</code> object and initializes it with
+ * the data read from the <code>InputStream</code> inStream. The data
+ * is assumed to be in the specified encoding. See Appendix A in the
+ * <a href="../../../../guide/security/certpath/CertPathProgGuide.html#AppA">
+ * Java Certification Path API Programmer's Guide</a>
+ * for information about standard encoding names and their formats.
+ *
+ * @param inStream an <code>InputStream</code> containing the data
+ * @param encoding the encoding used for the data
+ *
+ * @return a <code>CertPath</code> initialized with the data from the
+ * <code>InputStream</code>
+ *
+ * @exception CertificateException if an exception occurs while decoding or
+ * the encoding requested is not supported
+ */
+ public final CertPath generateCertPath(InputStream inStream, String encoding)
+ throws CertificateException
+ {
+ return certFacSpi.engineGenerateCertPath(inStream, encoding);
+ }
+
+ /**
+ * Generates a <code>CertPath</code> object and initializes it with
+ * a <code>List</code> of <code>Certificate</code>s.<br />
+ * <br />
+ * The certificates supplied must be of a type supported by the
+ * <code>CertificateFactory</code>. They will be copied out of the supplied
+ * <code>List</code> object.
+ *
+ * @param certificates a <code>List</code> of <code>Certificate</code>s
+ *
+ * @return a <code>CertPath</code> initialized with the supplied list of
+ * certificates
+ *
+ * @exception CertificateException if an exception occurs
+ */
+ public final CertPath generateCertPath(List certificates)
+ throws CertificateException
+ {
+ return certFacSpi.engineGenerateCertPath(certificates);
+ }
+
+ public static final CertificateFactory getInstance(String type)
+ throws CertificateException
+ {
+ try
+ {
+ CertUtil.Implementation imp = CertUtil.getImplementation("CertificateFactory", type, (String)null);
+
+ if (imp != null)
+ {
+ return new CertificateFactory((CertificateFactorySpi)imp.getEngine(), imp.getProvider(), type);
+ }
+
+ throw new CertificateException("can't find type " + type);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new CertificateException(type + " not found");
+ }
+ }
+
+ public static final CertificateFactory getInstance(
+ String type,
+ String provider)
+ throws CertificateException, NoSuchProviderException
+ {
+ CertUtil.Implementation imp = CertUtil.getImplementation("CertificateFactory", type, provider);
+
+ if (imp != null)
+ {
+ return new CertificateFactory((CertificateFactorySpi)imp.getEngine(), imp.getProvider(), type);
+ }
+
+ throw new CertificateException("can't find type " + type);
+ }
+
+ public final Provider getProvider()
+ {
+ return provider;
+ }
+
+ public final String getType()
+ {
+ return type;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java
new file mode 100644
index 000000000..1bed77211
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java
@@ -0,0 +1,99 @@
+package org.spongycastle.jce.cert;
+
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class CertificateFactorySpi
+ extends java.security.cert.CertificateFactorySpi
+{
+ public CertificateFactorySpi()
+ {
+ }
+
+ /**
+ * Returns an iteration of the <code>CertPath</code> encodings supported
+ * by this certificate factory, with the default encoding first. See
+ * Appendix A in the
+ * Java Certification Path API Programmer's Guide
+ * for information about standard encoding names.<br />
+ * <br />
+ * Attempts to modify the returned <code>Iterator</code> via its
+ * <code>remove</code> method result in an
+ * <code>UnsupportedOperationException</code>.<br />
+ * <br />
+ * This method was added to version 1.4 of the Java 2 Platform
+ * Standard Edition. In order to maintain backwards compatibility with
+ * existing service providers, this method cannot be <code>abstract</code>
+ * and by default throws an <code>UnsupportedOperationException</code>.
+ *
+ * @return an <code>Iterator</code> over the names of the supported
+ * <code>CertPath</code> encodings (as <code>String</code>s)
+ *
+ * @exception UnsupportedOperationException if the method is not supported
+ */
+ public abstract Iterator engineGetCertPathEncodings();
+
+ /**
+ * Generates a <code>CertPath</code> object and initializes it with
+ * the data read from the <code>InputStream</code> inStream. The data
+ * is assumed to be in the default encoding.
+ *
+ * @param inStream an <code>InputStream</code> containing the data
+ *
+ * @return a <code>CertPath</code> initialized with the data from the
+ * <code>InputStream</code>
+ *
+ * @exception CertificateException if an exception occurs while decoding
+ */
+ public abstract CertPath engineGenerateCertPath(InputStream inStream)
+ throws CertificateException;
+
+ /**
+ * Generates a <code>CertPath</code> object and initializes it with
+ * the data read from the <code>InputStream</code> inStream. The data
+ * is assumed to be in the specified encoding.<br />
+ * <br />
+ * This method was added to version 1.4 of the Java 2 Platform
+ * Standard Edition. In order to maintain backwards compatibility with
+ * existing service providers, this method cannot be <code>abstract</code>
+ * and by default throws an <code>UnsupportedOperationException</code>.
+ *
+ * @param inStream an <code>InputStream</code> containing the data
+ * @param encoding the encoding used for the data
+ *
+ * @return a <code>CertPath</code> initialized with the data from the
+ * <code>InputStream</code>
+ *
+ * @exception CertificateException if an exception occurs while decoding or
+ * the encoding requested is not supported
+ * @exception UnsupportedOperationException if the method is not supported
+ */
+ public abstract CertPath engineGenerateCertPath(InputStream inStream, String encoding)
+ throws CertificateException;
+
+ /**
+ * Generates a <code>CertPath</code> object and initializes it with
+ * a <code>List</code> of <code>Certificate</code>s.<br />
+ * <br />
+ * The certificates supplied must be of a type supported by the
+ * <code>CertificateFactory</code>. They will be copied out of the supplied
+ * <code>List</code> object.<br />
+ * <br />
+ * This method was added to version 1.4 of the Java 2 Platform
+ * Standard Edition. In order to maintain backwards compatibility with
+ * existing service providers, this method cannot be <code>abstract</code>
+ * and by default throws an <code>UnsupportedOperationException</code>.
+ *
+ * @param certificates a <code>List</code> of <code>Certificate</code>s
+ *
+ * @return a <code>CertPath</code> initialized with the supplied list of
+ * certificates
+ *
+ * @exception CertificateException if an exception occurs
+ * @exception UnsupportedOperationException if the method is not supported
+ */
+ public abstract CertPath engineGenerateCertPath(List certificates)
+ throws CertificateException;
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java
new file mode 100644
index 000000000..1692fefa8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java
@@ -0,0 +1,124 @@
+package org.spongycastle.jce.cert;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Parameters used as input for the Collection <code>CertStore</code>
+ * algorithm.<br />
+ * <br />
+ * This class is used to provide necessary configuration parameters
+ * to implementations of the Collection <code>CertStore</code>
+ * algorithm. The only parameter included in this class is the
+ * <code>Collection</code> from which the <code>CertStore</code> will
+ * retrieve certificates and CRLs.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see java.util.Collection
+ * @see CertStore
+ **/
+public class CollectionCertStoreParameters implements CertStoreParameters
+{
+ private Collection collection;
+
+ /**
+ * Creates an instance of <code>CollectionCertStoreParameters</code> which
+ * will allow certificates and CRLs to be retrieved from the specified
+ * <code>Collection</code>. If the specified <code>Collection</code>
+ * contains an object that is not a <code>Certificate</code> or
+ * <code>CRL</code>, that object will be ignored by the Collection
+ * <code>CertStore</code>.<br />
+ * <br />
+ * The <code>Collection</code> is <b>not</b> copied. Instead, a reference
+ * is used. This allows the caller to subsequently add or remove
+ * <code>Certificates</code> or <code>CRL</code>s from the
+ * <code>Collection</code>, thus changing the set of
+ * <code>Certificates</code> or <code>CRL</code>s available to the
+ * Collection <code>CertStore</code>. The Collection
+ * <code>CertStore</code> will not modify the contents of the
+ * <code>Collection</code>.<br />
+ * <br />
+ * If the <code>Collection</code> will be modified by one thread while
+ * another thread is calling a method of a Collection <code>CertStore</code>
+ * that has been initialized with this <code>Collection</code>, the
+ * <code>Collection</code> must have fail-fast iterators.
+ *
+ * @param collection
+ * a <code>Collection</code> of <code>Certificate</code>s
+ * and <code>CRL</code>s
+ *
+ * @exception NullPointerException
+ * if <code>collection</code> is <code>null</code>
+ */
+ public CollectionCertStoreParameters(Collection collection)
+ {
+ if (collection == null)
+ {
+ throw new NullPointerException("collection must be non-null");
+ }
+ this.collection = collection;
+ }
+
+ /**
+ * Creates an instance of <code>CollectionCertStoreParameters</code> with
+ * the an empty Collection.
+ */
+ public CollectionCertStoreParameters()
+ {
+ collection = new ArrayList();
+ }
+
+ /**
+ * Returns the <code>Collection</code> from which <code>Certificate</code>s
+ * and <code>CRL</code>s are retrieved. This is <b>not</b> a copy of the
+ * <code>Collection</code>, it is a reference. This allows the caller to
+ * subsequently add or remove <code>Certificates</code> or
+ * <code>CRL</code>s from the <code>Collection</code>.
+ *
+ * @return the <code>Collection</code> (never null)
+ */
+ public Collection getCollection()
+ {
+ return collection;
+ }
+
+ /**
+ * Returns a copy of this object. Note that only a reference to the
+ * <code>Collection</code> is copied, and not the contents.
+ *
+ * @return the copy
+ */
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ /* Cannot happen */
+ throw new InternalError(e.toString());
+ }
+ }
+
+ /**
+ * Returns a formatted string describing the parameters.
+ *
+ * @return a formatted string describing the parameters
+ */
+ public String toString()
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("CollectionCertStoreParameters: [\n collections:\n");
+ s.append(getCollection());
+ s.append("\n]");
+ return s.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java
new file mode 100644
index 000000000..306c66610
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java
@@ -0,0 +1,138 @@
+package org.spongycastle.jce.cert;
+
+/**
+ * Parameters used as input for the LDAP <code>CertStore</code> algorithm.<br />
+ * <br />
+ * This class is used to provide necessary configuration parameters (server
+ * name and port number) to implementations of the LDAP <code>CertStore</code>
+ * algorithm.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertStore
+ **/
+public class LDAPCertStoreParameters implements CertStoreParameters
+{
+ private static final int LDAP_DEFAULT_PORT = 389;
+
+ /**
+ * the port number of the LDAP server
+ */
+ private String serverName;
+
+ /**
+ * the DNS name of the LDAP server
+ */
+ private int port;
+
+ /**
+ * Creates an instance of <code>LDAPCertStoreParameters</code> with the
+ * default parameter values (server name "localhost", port 389).
+ */
+ public LDAPCertStoreParameters()
+ {
+ this("localhost", LDAP_DEFAULT_PORT);
+ }
+
+ /**
+ * Creates an instance of <code>LDAPCertStoreParameters</code> with the
+ * specified server name and a default port of 389.
+ *
+ * @param serverName
+ * the DNS name of the LDAP server
+ *
+ * @exception NullPointerException
+ * if <code>serverName</code> is <code>null</code>
+ */
+ public LDAPCertStoreParameters(String serverName)
+ {
+ this(serverName, LDAP_DEFAULT_PORT);
+ }
+
+ /**
+ * Creates an instance of <code>LDAPCertStoreParameters</code> with the
+ * specified parameter values.
+ *
+ * @param serverName
+ * the DNS name of the LDAP server
+ * @param port
+ * the port number of the LDAP server
+ *
+ * @exception NullPointerException
+ * if <code>serverName</code> is <code>null</code>
+ */
+ public LDAPCertStoreParameters(String serverName, int port)
+ {
+ if (serverName == null)
+ {
+ throw new NullPointerException("serverName must be non-null");
+ }
+ this.serverName = serverName;
+ this.port = port;
+ }
+
+ /**
+ * Returns the DNS name of the LDAP server.
+ *
+ * @return the name (not <code>null</code>)
+ */
+ public String getServerName()
+ {
+ return serverName;
+ }
+
+ /**
+ * Returns the port number of the LDAP server.
+ *
+ * @return the port number
+ */
+ public int getPort()
+ {
+ return port;
+ }
+
+ /**
+ * Returns a copy of this object. Changes to the copy will not affect the
+ * original and vice versa.<br />
+ * <br />
+ * Note: this method currently performs a shallow copy of the object (simply
+ * calls <code>Object.clone()</code>). This may be changed in a future
+ * revision to perform a deep copy if new parameters are added that should
+ * not be shared.
+ *
+ * @return the copy
+ */
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ /* Cannot happen */
+ throw new InternalError(e.toString());
+ }
+ }
+
+ /**
+ * Returns a formatted string describing the parameters.
+ *
+ * @return a formatted string describing the parameters
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("LDAPCertStoreParameters: [\n");
+ sb.append(" serverName: ").append(serverName).append('\n');
+ sb.append(" port: ").append(port).append('\n');
+ sb.append(']');
+ return sb.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java
new file mode 100644
index 000000000..79136ad39
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java
@@ -0,0 +1,190 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.Set;
+
+/**
+ * Parameters used as input for the PKIX <code>CertPathBuilder</code>
+ * algorithm.<br />
+ * <br />
+ * A PKIX <code>CertPathBuilder</code> uses these parameters to {@link
+ * CertPathBuilder#build build} a <code>CertPath</code> which has been
+ * validated according to the PKIX certification path validation algorithm.<br />
+ * <br />
+ * To instantiate a <code>PKIXBuilderParameters</code> object, an
+ * application must specify one or more <i>most-trusted CAs</i> as defined by
+ * the PKIX certification path validation algorithm. The most-trusted CA
+ * can be specified using one of two constructors. An application
+ * can call {@link #PKIXBuilderParameters(Set, CertSelector)
+ * PKIXBuilderParameters(Set, CertSelector)}, specifying a
+ * <code>Set</code> of <code>TrustAnchor</code> objects, each of which
+ * identifies a most-trusted CA. Alternatively, an application can call
+ * {@link #PKIXBuilderParameters(KeyStore, CertSelector)
+ * PKIXBuilderParameters(KeyStore, CertSelector)}, specifying a
+ * <code>KeyStore</code> instance containing trusted certificate entries, each
+ * of which will be considered as a most-trusted CA.<br />
+ * <br />
+ * In addition, an application must specify constraints on the target
+ * certificate that the <code>CertPathBuilder</code> will attempt
+ * to build a path to. The constraints are specified as a
+ * <code>CertSelector</code> object. These constraints should provide the
+ * <code>CertPathBuilder</code> with enough search criteria to find the target
+ * certificate. Minimal criteria for an <code>X509Certificate</code> usually
+ * include the subject name and/or one or more subject alternative names.
+ * If enough criteria is not specified, the <code>CertPathBuilder</code>
+ * may throw a <code>CertPathBuilderException</code>.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathBuilder
+ **/
+public class PKIXBuilderParameters extends PKIXParameters
+{
+ private int maxPathLength = 5;
+
+ /**
+ * Creates an instance of <code>PKIXBuilderParameters</code> with the
+ * specified <code>Set</code> of most-trusted CAs. Each element of the set
+ * is a {@link TrustAnchor TrustAnchor}.<br />
+ * <br />
+ * Note that the <code>Set</code> is copied to protect against subsequent
+ * modifications.
+ *
+ * @param trustAnchors
+ * a <code>Set</code> of <code>TrustAnchor</code>s
+ * @param targetConstraints
+ * a <code>CertSelector</code> specifying the constraints on
+ * the target certificate
+ *
+ * @exception InvalidAlgorithmParameterException
+ * if <code>trustAnchors</code> is empty
+ * <code>(trustAnchors.isEmpty() == true)</code>
+ * @exception NullPointerException
+ * if <code>trustAnchors</code> is <code>null</code>
+ * @exception ClassCastException
+ * if any of the elements of <code>trustAnchors</code> are
+ * not of type <code>java.security.cert.TrustAnchor</code>
+ */
+ public PKIXBuilderParameters(
+ Set trustAnchors,
+ CertSelector targetConstraints)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ setTargetCertConstraints(targetConstraints);
+ }
+
+ /**
+ * Creates an instance of <code>PKIXBuilderParameters</code> that
+ * populates the set of most-trusted CAs from the trusted certificate
+ * entries contained in the specified <code>KeyStore</code>. Only
+ * keystore entries that contain trusted <code>X509Certificate</code>s
+ * are considered; all other certificate types are ignored.
+ *
+ * @param keystore
+ * a <code>KeyStore</code> from which the set of most-trusted
+ * CAs will be populated
+ * @param targetConstraints
+ * a <code>CertSelector</code> specifying the constraints on
+ * the target certificate
+ *
+ * @exception KeyStoreException
+ * if <code>keystore</code> has not been initialized
+ * @exception InvalidAlgorithmParameterException
+ * if <code>keystore</code> does not contain at least one
+ * trusted certificate entry
+ * @exception NullPointerException
+ * if <code>keystore</code> is <code>null</code>
+ */
+ public PKIXBuilderParameters(
+ KeyStore keystore,
+ CertSelector targetConstraints) throws KeyStoreException,
+ InvalidAlgorithmParameterException
+ {
+ super(keystore);
+ setTargetCertConstraints(targetConstraints);
+ }
+
+ /**
+ * Sets the value of the maximum number of non-self-issued intermediate
+ * certificates that may exist in a certification path. A certificate is
+ * self-issued if the DNs that appear in the subject and issuer fields are
+ * identical and are not empty. Note that the last certificate in a
+ * certification path is not an intermediate certificate, and is not
+ * included in this limit. Usually the last certificate is an end entity
+ * certificate, but it can be a CA certificate. A PKIX
+ * <code>CertPathBuilder</code> instance must not build paths longer than
+ * the length specified.<br />
+ * <br />
+ * A value of 0 implies that the path can only contain a single certificate.
+ * A value of -1 implies that the path length is unconstrained (i.e. there
+ * is no maximum). The default maximum path length, if not specified, is 5.
+ * Setting a value less than -1 will cause an exception to be thrown.<br />
+ * <br />
+ * If any of the CA certificates contain the
+ * <code>BasicConstraintsExtension</code>, the value of the
+ * <code>pathLenConstraint</code> field of the extension overrides the
+ * maximum path length parameter whenever the result is a certification path
+ * of smaller length.
+ *
+ * @param maxPathLength
+ * the maximum number of non-self-issued intermediate
+ * certificates that may exist in a certification path
+ *
+ * @exception InvalidParameterException
+ * if <code>maxPathLength</code> is set to a value less
+ * than -1
+ *
+ * @see #getMaxPathLength
+ */
+ public void setMaxPathLength(int maxPathLength)
+ {
+ if (maxPathLength < -1)
+ {
+ throw new InvalidParameterException(
+ "the maximum path length parameter can not be less than -1");
+ }
+ this.maxPathLength = maxPathLength;
+ }
+
+ /**
+ * Returns the value of the maximum number of intermediate non-self-issued
+ * certificates that may exist in a certification path. See the
+ * {@link #setMaxPathLength} method for more details.
+ *
+ * @return the maximum number of non-self-issued intermediate certificates
+ * that may exist in a certification path, or -1 if there is no
+ * limit
+ *
+ * @see #setMaxPathLength
+ */
+ public int getMaxPathLength()
+ {
+ return maxPathLength;
+ }
+
+ /**
+ * Returns a formatted string describing the parameters.
+ *
+ * @return a formatted string describing the parameters
+ */
+ public String toString()
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("PKIXBuilderParameters [\n");
+ s.append(super.toString());
+ s.append(" Maximum Path Length: ");
+ s.append(getMaxPathLength());
+ s.append("\n]\n");
+ return s.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java
new file mode 100644
index 000000000..0288b8506
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java
@@ -0,0 +1,103 @@
+package org.spongycastle.jce.cert;
+
+import java.security.PublicKey;
+
+/**
+ * This class represents the successful result of the PKIX certification
+ * path builder algorithm. All certification paths that are built and
+ * returned using this algorithm are also validated according to the PKIX
+ * certification path validation algorithm.<br />
+ * <br />
+ * Instances of <code>PKIXCertPathBuilderResult</code> are returned by
+ * the <code>build</code> method of <code>CertPathBuilder</code>
+ * objects implementing the PKIX algorithm.<br />
+ * <br />
+ * All <code>PKIXCertPathBuilderResult</code> objects contain the
+ * certification path constructed by the build algorithm, the
+ * valid policy tree and subject public key resulting from the build
+ * algorithm, and a <code>TrustAnchor</code> describing the certification
+ * authority (CA) that served as a trust anchor for the certification path.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathBuilderResult
+ *
+ **/
+public class PKIXCertPathBuilderResult extends PKIXCertPathValidatorResult
+ implements CertPathBuilderResult
+{
+ private CertPath certPath;
+
+ /**
+ * Creates an instance of <code>PKIXCertPathBuilderResult</code>
+ * containing the specified parameters.
+ *
+ * @param certPath
+ * the validated <code>CertPath</code>
+ * @param trustAnchor
+ * a <code>TrustAnchor</code> describing the CA that served as
+ * a trust anchor for the certification path
+ * @param policyTree
+ * the immutable valid policy tree, or <code>null</code> if
+ * there are no valid policies
+ * @param subjectPublicKey
+ * the public key of the subject
+ *
+ * @exception NullPointerException
+ * if the <code>certPath</code>, <code>trustAnchor</code>
+ * or <code>subjectPublicKey</code> parameters are
+ * <code>null</code>
+ */
+ public PKIXCertPathBuilderResult(
+ CertPath certPath,
+ TrustAnchor trustAnchor,
+ PolicyNode policyTree,
+ PublicKey subjectPublicKey)
+ {
+ super(trustAnchor, policyTree, subjectPublicKey);
+ if (certPath == null)
+ {
+ throw new NullPointerException("certPath must be non-null");
+ }
+ this.certPath = certPath;
+ }
+
+ /**
+ * Returns the built and validated certification path. The
+ * <code>CertPath</code> object does not include the trust anchor.
+ * Instead, use the {@link #getTrustAnchor() getTrustAnchor()} method to
+ * obtain the <code>TrustAnchor</code> that served as the trust anchor for
+ * the certification path.
+ *
+ * @return the built and validated <code>CertPath</code> (never
+ * <code>null</code>)
+ */
+ public CertPath getCertPath()
+ {
+ return certPath;
+ }
+
+ /**
+ * Return a printable representation of this
+ * <code>PKIXCertPathBuilderResult</code>.
+ *
+ * @return a <code>String</code> describing the contents of this
+ * <code>PKIXCertPathBuilderResult</code>
+ */
+ public String toString()
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("PKIXCertPathBuilderResult: [\n");
+ s.append(" Certification Path: ").append(getCertPath()).append('\n');
+ s.append(" Trust Anchor: ").append(getTrustAnchor()).append('\n');
+ s.append(" Policy Tree: ").append(getPolicyTree()).append('\n');
+ s.append(" Subject Public Key: ").append(getPublicKey()).append("\n]");
+ return s.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java
new file mode 100644
index 000000000..07c71ca27
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java
@@ -0,0 +1,163 @@
+package org.spongycastle.jce.cert;
+
+import java.security.cert.Certificate;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * An abstract class that performs one or more checks on an
+ * <code>X509Certificate</code>. <br />
+ * <br />
+ * A concrete implementation of the <code>PKIXCertPathChecker</code> class
+ * can be created to extend the PKIX certification path validation algorithm.
+ * For example, an implementation may check for and process a critical private
+ * extension of each certificate in a certification path.<br />
+ * <br />
+ * Instances of <code>PKIXCertPathChecker</code> are passed as parameters
+ * using the {@link PKIXParameters#setCertPathCheckers setCertPathCheckers}
+ * or {@link PKIXParameters#addCertPathChecker addCertPathChecker} methods
+ * of the <code>PKIXParameters</code> and <code>PKIXBuilderParameters</code>
+ * class. Each of the <code>PKIXCertPathChecker</code>s {@link #check check}
+ * methods will be called, in turn, for each certificate processed by a PKIX
+ * <code>CertPathValidator</code> or <code>CertPathBuilder</code>
+ * implementation.<br />
+ * <br />
+ * A <code>PKIXCertPathChecker</code> may be called multiple times on
+ * successive certificates in a certification path. Concrete subclasses
+ * are expected to maintain any internal state that may be necessary to
+ * check successive certificates. The {@link #init init} method is used
+ * to initialize the internal state of the checker so that the certificates
+ * of a new certification path may be checked. A stateful implementation
+ * <b>must</b> override the {@link #clone clone} method if necessary in
+ * order to allow a PKIX <code>CertPathBuilder</code> to efficiently
+ * backtrack and try other paths. In these situations, the
+ * <code>CertPathBuilder</code> is able to restore prior path validation
+ * states by restoring the cloned <code>PKIXCertPathChecker</code>s.<br />
+ * <br />
+ * The order in which the certificates are presented to the
+ * <code>PKIXCertPathChecker</code> may be either in the forward direction
+ * (from target to most-trusted CA) or in the reverse direction (from
+ * most-trusted CA to target). A <code>PKIXCertPathChecker</code> implementation
+ * <b>must</b> support reverse checking (the ability to perform its checks when
+ * it is presented with certificates in the reverse direction) and <b>may</b>
+ * support forward checking (the ability to perform its checks when it is
+ * presented with certificates in the forward direction). The
+ * {@link #isForwardCheckingSupported isForwardCheckingSupported} method
+ * indicates whether forward checking is supported.<br />
+ * <br />
+ * Additional input parameters required for executing the check may be
+ * specified through constructors of concrete implementations of this class.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see PKIXParameters
+ * @see PKIXBuilderParameters
+ **/
+public abstract class PKIXCertPathChecker implements Cloneable
+{
+
+ /**
+ * Default constructor.
+ */
+ protected PKIXCertPathChecker()
+ {
+ }
+
+ /**
+ * Initializes the internal state of this <code>PKIXCertPathChecker</code>.
+ * <p>
+ * The <code>forward</code> flag specifies the order that certificates
+ * will be passed to the {@link #check check} method (forward or reverse). A
+ * <code>PKIXCertPathChecker</code> <b>must</b> support reverse checking
+ * and <b>may</b> support forward checking.
+ *
+ * @param forward
+ * the order that certificates are presented to the
+ * <code>check</code> method. If <code>true</code>,
+ * certificates are presented from target to most-trusted CA
+ * (forward); if <code>false</code>, from most-trusted CA to
+ * target (reverse).
+ * @exception CertPathValidatorException
+ * if this <code>PKIXCertPathChecker</code> is unable to
+ * check certificates in the specified order; it should never
+ * be thrown if the forward flag is false since reverse
+ * checking must be supported
+ */
+ public abstract void init(boolean forward)
+ throws CertPathValidatorException;
+
+ /**
+ * Indicates if forward checking is supported. Forward checking refers to
+ * the ability of the <code>PKIXCertPathChecker</code> to perform its
+ * checks when certificates are presented to the <code>check</code> method
+ * in the forward direction (from target to most-trusted CA).
+ *
+ * @return <code>true</code> if forward checking is supported,
+ * <code>false</code> otherwise
+ */
+ public abstract boolean isForwardCheckingSupported();
+
+ /**
+ * Returns an immutable <code>Set</code> of X.509 certificate extensions
+ * that this <code>PKIXCertPathChecker</code> supports (i.e. recognizes,
+ * is able to process), or <code>null</code> if no extensions are
+ * supported.
+ * <p>
+ * Each element of the set is a <code>String</code> representing the
+ * Object Identifier (OID) of the X.509 extension that is supported. The OID
+ * is represented by a set of nonnegative integers separated by periods.
+ * <p>
+ * All X.509 certificate extensions that a <code>PKIXCertPathChecker</code>
+ * might possibly be able to process should be included in the set.
+ *
+ * @return an immutable <code>Set</code> of X.509 extension OIDs (in
+ * <code>String</code> format) supported by this
+ * <code>PKIXCertPathChecker</code>, or <code>null</code> if no
+ * extensions are supported
+ */
+ public abstract Set getSupportedExtensions();
+
+ /**
+ * Performs the check(s) on the specified certificate using its internal
+ * state and removes any critical extensions that it processes from the
+ * specified collection of OID strings that represent the unresolved
+ * critical extensions. The certificates are presented in the order
+ * specified by the <code>init</code> method.
+ *
+ * @param cert
+ * the <code>Certificate</code> to be checked
+ * @param unresolvedCritExts
+ * a <code>Collection</code> of OID strings representing the
+ * current set of unresolved critical extensions
+ * @exception CertPathValidatorException
+ * if the specified certificate does not pass the check
+ */
+ public abstract void check(Certificate cert, Collection unresolvedCritExts)
+ throws CertPathValidatorException;
+
+ /**
+ * Returns a clone of this object. Calls the <code>Object.clone()</code>
+ * method. All subclasses which maintain state must support and override
+ * this method, if necessary.
+ *
+ * @return a copy of this <code>PKIXCertPathChecker</code>
+ */
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException ex)
+ {
+ /* Cannot happen */
+ throw new InternalError(ex.toString());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java
new file mode 100644
index 000000000..aa9b530f4
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java
@@ -0,0 +1,150 @@
+package org.spongycastle.jce.cert;
+
+import java.security.PublicKey;
+
+/**
+ * This class represents the successful result of the PKIX certification path
+ * validation algorithm. <br />
+ * <br />
+ * Instances of <code>PKIXCertPathValidatorResult</code> are returned by the
+ * {@link CertPathValidator#validate validate} method of
+ * <code>CertPathValidator</code> objects implementing the PKIX algorithm.<br />
+ * <br />
+ * All <code>PKIXCertPathValidatorResult</code> objects contain the valid
+ * policy tree and subject public key resulting from the validation algorithm,
+ * as well as a <code>TrustAnchor</code> describing the certification
+ * authority (CA) that served as a trust anchor for the certification path.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single object
+ * concurrently should synchronize amongst themselves and provide the necessary
+ * locking. Multiple threads each manipulating separate objects need not
+ * synchronize.
+ *
+ * @see CertPathValidatorResult
+ */
+public class PKIXCertPathValidatorResult implements CertPathValidatorResult
+{
+ private TrustAnchor trustAnchor;
+
+ private PolicyNode policyTree;
+
+ private PublicKey subjectPublicKey;
+
+ /**
+ * Creates an instance of <code>PKIXCertPathValidatorResult</code>
+ * containing the specified parameters.
+ *
+ * @param trustAnchor
+ * a <code>TrustAnchor</code> describing the CA that served as
+ * a trust anchor for the certification path
+ * @param policyTree
+ * the immutable valid policy tree, or <code>null</code> if
+ * there are no valid policies
+ * @param subjectPublicKey
+ * the public key of the subject
+ *
+ * @exception NullPointerException
+ * if the <code>subjectPublicKey</code> or
+ * <code>trustAnchor</code> parameters are
+ * <code>null</code>
+ */
+ public PKIXCertPathValidatorResult(
+ TrustAnchor trustAnchor,
+ PolicyNode policyTree,
+ PublicKey subjectPublicKey)
+ {
+ if (subjectPublicKey == null)
+ {
+ throw new NullPointerException("subjectPublicKey must be non-null");
+ }
+ if (trustAnchor == null)
+ {
+ throw new NullPointerException("trustAnchor must be non-null");
+ }
+
+ this.trustAnchor = trustAnchor;
+ this.policyTree = policyTree;
+ this.subjectPublicKey = subjectPublicKey;
+ }
+
+ /**
+ * Returns the <code>TrustAnchor</code> describing the CA that served as a
+ * trust anchor for the certification path.
+ *
+ * @return the <code>TrustAnchor</code> (never <code>null</code>)
+ */
+ public TrustAnchor getTrustAnchor()
+ {
+ return trustAnchor;
+ }
+
+ /**
+ * Returns the root node of the valid policy tree resulting from the PKIX
+ * certification path validation algorithm. The <code>PolicyNode</code>
+ * object that is returned and any objects that it returns through public
+ * methods are immutable.<br />
+ * <br />
+ * Most applications will not need to examine the valid policy tree. They
+ * can achieve their policy processing goals by setting the policy-related
+ * parameters in <code>PKIXParameters</code>. However, more sophisticated
+ * applications, especially those that process policy qualifiers, may need
+ * to traverse the valid policy tree using the
+ * {@link PolicyNode#getParent PolicyNode.getParent} and
+ * {@link PolicyNode#getChildren PolicyNode.getChildren} methods.
+ *
+ * @return the root node of the valid policy tree, or <code>null</code> if
+ * there are no valid policies
+ */
+ public PolicyNode getPolicyTree()
+ {
+ return policyTree;
+ }
+
+ /**
+ * Returns the public key of the subject (target) of the certification path,
+ * including any inherited public key parameters if applicable.
+ *
+ * @return the public key of the subject (never <code>null</code>)
+ */
+ public PublicKey getPublicKey()
+ {
+ return subjectPublicKey;
+ }
+
+ /**
+ * Returns a copy of this object.
+ *
+ * @return the copy
+ */
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException ex)
+ {
+ throw new InternalError(ex.toString());
+ }
+ }
+
+ /**
+ * Return a printable representation of this
+ * <code>PKIXCertPathValidatorResult</code>.
+ *
+ * @return a <code>String</code> describing the contents of this
+ * <code>PKIXCertPathValidatorResult</code>
+ */
+ public String toString()
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("PKIXCertPathValidatorResult: [ \n");
+ s.append(" Trust Anchor: ").append(getTrustAnchor()).append('\n');
+ s.append(" Policy Tree: ").append(getPolicyTree()).append('\n');
+ s.append(" Subject Public Key: ").append(getPublicKey()).append("\n]");
+ return s.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java
new file mode 100644
index 000000000..a9d2d3835
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java
@@ -0,0 +1,844 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Parameters used as input for the PKIX CertPathValidator algorithm.<br />
+ * <br />
+ * A PKIX <code>CertPathValidator</code> uses these parameters to validate a
+ * <code>CertPath</code> according to the PKIX certification path validation
+ * algorithm.<br />
+ * <br />
+ * To instantiate a <code>PKIXParameters</code> object, an application must
+ * specify one or more <i>most-trusted CAs</i> as defined by the PKIX
+ * certification path validation algorithm. The most-trusted CAs can be
+ * specified using one of two constructors. An application can call
+ * {@link #PKIXParameters(Set)}, specifying a Set of <code>TrustAnchor</code>
+ * objects, each of which identify a most-trusted CA. Alternatively, an
+ * application can call {@link #PKIXParameters(KeyStore)}, specifying a
+ * <code>KeyStore</code> instance containing trusted certificate entries, each
+ * of which will be considered as a most-trusted CA.<br />
+ * <br />
+ * Once a <code>PKIXParameters</code> object has been created, other
+ * parameters can be specified (by calling {@link #setInitialPolicies} or
+ * {@link #setDate}, for instance) and then the <code>PKIXParameters</code>
+ * is passed along with the <code>CertPath</code> to be validated to
+ * {@link CertPathValidator#validate}.<br />
+ * <br />
+ * Any parameter that is not set (or is set to null) will be set to the default
+ * value for that parameter. The default value for the date parameter is null,
+ * which indicates the current time when the path is validated. The default for
+ * the remaining parameters is the least constrained.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single object
+ * concurrently should synchronize amongst themselves and provide the necessary
+ * locking. Multiple threads each manipulating separate objects need not
+ * synchronize.
+ *
+ * @see CertPathValidator
+ */
+public class PKIXParameters implements CertPathParameters
+{
+ private Set trustAnchors;
+
+ private Set initialPolicies = new HashSet();
+
+ private List certStores = new ArrayList();
+
+ private CertSelector certSelector;
+
+ private List certPathCheckers = new ArrayList();
+
+ private boolean revocationEnabled = true;
+
+ private boolean explicitPolicyRequired = false;
+
+ private boolean policyMappingInhibited = false;
+
+ private boolean anyPolicyInhibited = false;
+
+ private boolean policyQualifiersRejected = true;
+
+ private Date date;
+
+ private String sigProvider;
+
+ /**
+ * Creates an instance of PKIXParameters with the specified Set of
+ * most-trusted CAs. Each element of the set is a TrustAnchor.<br />
+ * <br />
+ * Note that the Set is copied to protect against subsequent modifications.
+ *
+ * @param trustAnchors
+ * a Set of TrustAnchors
+ *
+ * @exception InvalidAlgorithmParameterException
+ * if the specified Set is empty
+ * <code>(trustAnchors.isEmpty() == true)</code>
+ * @exception NullPointerException
+ * if the specified Set is <code>null</code>
+ * @exception ClassCastException
+ * if any of the elements in the Set are not of type
+ * <code>java.security.cert.TrustAnchor</code>
+ */
+ public PKIXParameters(Set trustAnchors)
+ throws InvalidAlgorithmParameterException
+ {
+ setTrustAnchors(trustAnchors);
+ }
+
+ /**
+ * Creates an instance of PKIXParameters that populates the set of
+ * most-trusted CAs from the trusted certificate entries contained in the
+ * specified KeyStore. Only keystore entries that contain trusted
+ * X509Certificates are considered; all other certificate types are ignored.
+ *
+ * @param keystore
+ * a KeyStore from which the set of most-trusted CAs will be
+ * populated
+ *
+ * @exception KeyStoreException
+ * if the keystore has not been initialized
+ * @exception InvalidAlgorithmParameterException
+ * if the keystore does not contain at least one trusted
+ * certificate entry
+ * @exception NullPointerException
+ * if the keystore is null
+ */
+ public PKIXParameters(KeyStore keystore) throws KeyStoreException,
+ InvalidAlgorithmParameterException
+ {
+ if (keystore == null)
+ {
+ throw new NullPointerException(
+ "the keystore parameter must be non-null");
+ }
+
+ Set trustAnchors = new HashSet();
+ String alias;
+ Certificate cert;
+ Enumeration enum = keystore.aliases();
+ while (enum.hasMoreElements())
+ {
+ alias = (String)enum.nextElement();
+ if (keystore.isCertificateEntry(alias))
+ {
+ cert = keystore.getCertificate(alias);
+ if (cert instanceof X509Certificate)
+ {
+ trustAnchors.add(new TrustAnchor((X509Certificate)cert,
+ null));
+ }
+ }
+ }
+ setTrustAnchors(trustAnchors);
+ }
+
+ /**
+ * Returns an immutable Set of the most-trusted CAs.
+ *
+ * @return an immutable <code>Set</code> of <code>TrustAnchors</code>
+ * (never <code>null</code>)
+ *
+ * @see #setTrustAnchors
+ */
+ public Set getTrustAnchors()
+ {
+ return Collections.unmodifiableSet(trustAnchors);
+ }
+
+ /**
+ * Sets the Set of most-trusted CAs.<br />
+ * <br />
+ * Note that the Set is copied to protect against subsequent modifications.<br />
+ * <br />
+ *
+ * @param trustAnchors
+ * a Set of TrustAnchors
+ *
+ * @exception InvalidAlgorithmParameterException
+ * if the specified Set is empty
+ * <code>(trustAnchors.isEmpty() == true)</code>
+ * @exception NullPointerException
+ * if the specified Set is <code>null</code>
+ * @exception ClassCastException
+ * if any of the elements in the set are not of type
+ * java.security.cert.TrustAnchor
+ *
+ * @see #getTrustAnchors
+ */
+ public void setTrustAnchors(Set trustAnchors)
+ throws InvalidAlgorithmParameterException
+ {
+ if (trustAnchors == null)
+ {
+ throw new NullPointerException(
+ "the trustAnchors parameter must be non-null");
+ }
+ if (trustAnchors.isEmpty())
+ {
+ throw new InvalidAlgorithmParameterException(
+ "the trustAnchors parameter must be non-empty");
+ }
+
+ Iterator iter = trustAnchors.iterator();
+ TrustAnchor obj;
+ this.trustAnchors = new HashSet();
+ while (iter.hasNext())
+ {
+ obj = (TrustAnchor)iter.next();
+ if (obj != null)
+ {
+ this.trustAnchors.add(obj);
+ }
+ }
+ }
+
+ /**
+ * Returns an immutable Set of initial policy identifiers (OID strings),
+ * indicating that any one of these policies would be acceptable to the
+ * certificate user for the purposes of certification path processing. The
+ * default return value is an empty <code>Set</code>, which is
+ * interpreted as meaning that any policy would be acceptable.
+ *
+ * @return an immutable <code>Set</code> of initial policy OIDs in String
+ * format, or an empty <code>Set</code> (implying any policy is
+ * acceptable). Never returns <code>null</code>.
+ *
+ * @see #setInitialPolicies(java.util.Set)
+ */
+ public Set getInitialPolicies()
+ {
+ Set returnSet = initialPolicies;
+ if (initialPolicies == null)
+ {
+ returnSet = new HashSet();
+ }
+
+ return Collections.unmodifiableSet(returnSet);
+ }
+
+ /**
+ * Sets the <code>Set</code> of initial policy identifiers (OID strings),
+ * indicating that any one of these policies would be acceptable to the
+ * certificate user for the purposes of certification path processing. By
+ * default, any policy is acceptable (i.e. all policies), so a user that
+ * wants to allow any policy as acceptable does not need to call this
+ * method, or can call it with an empty <code>Set</code> (or
+ * <code>null</code>).<br />
+ * <br />
+ * Note that the Set is copied to protect against subsequent modifications.<br />
+ * <br />
+ *
+ * @param initialPolicies
+ * a Set of initial policy OIDs in String format (or
+ * <code>null</code>)
+ *
+ * @exception ClassCastException
+ * if any of the elements in the set are not of type String
+ *
+ * @see #getInitialPolicies()
+ */
+ public void setInitialPolicies(Set initialPolicies)
+ {
+ if (initialPolicies == null || initialPolicies.isEmpty())
+ {
+ this.initialPolicies = null;
+ }
+ else
+ {
+ Iterator iter = initialPolicies.iterator();
+ this.initialPolicies = new HashSet();
+ String obj;
+ while (iter.hasNext())
+ {
+ obj = (String)iter.next();
+ if (obj != null)
+ {
+ this.initialPolicies.add(obj);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the list of CertStores to be used in finding certificates and CRLs.
+ * May be null, in which case no CertStores will be used. The first
+ * CertStores in the list may be preferred to those that appear later.<br />
+ * <br />
+ * Note that the List is copied to protect against subsequent modifications.<br />
+ * <br />
+ *
+ * @param stores
+ * a List of CertStores (or <code>null</code>)
+ *
+ * @exception ClassCastException
+ * if any of the elements in the list are not of type
+ * <code>java.security.cert.CertStore</code>
+ *
+ * @see #getCertStores()
+ */
+ public void setCertStores(List stores)
+ {
+ certStores = new ArrayList();
+ if (stores != null && !stores.isEmpty())
+ {
+ Iterator iter = stores.iterator();
+ CertStore obj;
+ while (iter.hasNext())
+ {
+ obj = (CertStore)iter.next();
+ if (obj != null)
+ {
+ certStores.add(obj);
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a CertStore to the end of the list of CertStores used in finding
+ * certificates and CRLs.
+ *
+ * @param store
+ * the <code>CertStore</code> to add. If
+ * <code>null</code<, the store is ignored (not added to
+ * list).
+ */
+ public void addCertStore(CertStore store)
+ {
+ if (store != null)
+ {
+ certStores.add(store);
+ }
+ }
+
+ /**
+ * Returns an immutable List of CertStores that are used to find
+ * certificates and CRLs.
+ *
+ * @return an immutable List of CertStores (may be empty, but never
+ * <code>null</code>)
+ *
+ * @see #setCertStores(java.util.List)
+ */
+ public List getCertStores()
+ {
+ return Collections.unmodifiableList(certStores);
+ }
+
+ /**
+ * Sets the RevocationEnabled flag. If this flag is true, the default
+ * revocation checking mechanism of the underlying PKIX service provider
+ * will be used. If this flag is false, the default revocation checking
+ * mechanism will be disabled (not used).<br />
+ * <br />
+ * When a <code>PKIXParameters</code> object is created, this flag is set
+ * to true. This setting reflects the most common strategy for checking
+ * revocation, since each service provider must support revocation checking
+ * to be PKIX compliant. Sophisticated applications should set this flag to
+ * false when it is not practical to use a PKIX service provider's default
+ * revocation checking mechanism or when an alternative revocation checking
+ * mechanism is to be substituted (by also calling the
+ * {@link #addCertPathChecker addCertPathChecker} or {@link
+ * #setCertPathCheckers setCertPathCheckers} methods).
+ *
+ * @param val
+ * the new value of the RevocationEnabled flag
+ */
+ public void setRevocationEnabled(boolean val)
+ {
+ revocationEnabled = val;
+ }
+
+ /**
+ * Checks the RevocationEnabled flag. If this flag is true, the default
+ * revocation checking mechanism of the underlying PKIX service provider
+ * will be used. If this flag is false, the default revocation checking
+ * mechanism will be disabled (not used). See the setRevocationEnabled
+ * method for more details on setting the value of this flag.
+ *
+ * @return the current value of the RevocationEnabled flag
+ */
+ public boolean isRevocationEnabled()
+ {
+ return revocationEnabled;
+ }
+
+ /**
+ * Sets the ExplicitPolicyRequired flag. If this flag is true, an acceptable
+ * policy needs to be explicitly identified in every certificate. By
+ * default, the ExplicitPolicyRequired flag is false.
+ *
+ * @param val
+ * true if explicit policy is to be required, false otherwise
+ */
+ public void setExplicitPolicyRequired(boolean val)
+ {
+ explicitPolicyRequired = val;
+ }
+
+ /**
+ * Checks if explicit policy is required. If this flag is true, an
+ * acceptable policy needs to be explicitly identified in every certificate.
+ * By default, the ExplicitPolicyRequired flag is false.
+ *
+ * @return true if explicit policy is required, false otherwise
+ */
+ public boolean isExplicitPolicyRequired()
+ {
+ return explicitPolicyRequired;
+ }
+
+ /**
+ * Sets the PolicyMappingInhibited flag. If this flag is true, policy
+ * mapping is inhibited. By default, policy mapping is not inhibited (the
+ * flag is false).
+ *
+ * @param val
+ * true if policy mapping is to be inhibited, false otherwise
+ */
+ public void setPolicyMappingInhibited(boolean val)
+ {
+ policyMappingInhibited = val;
+ }
+
+ /**
+ * Checks if policy mapping is inhibited. If this flag is true, policy
+ * mapping is inhibited. By default, policy mapping is not inhibited (the
+ * flag is false).
+ *
+ * @return true if policy mapping is inhibited, false otherwise
+ */
+ public boolean isPolicyMappingInhibited()
+ {
+ return policyMappingInhibited;
+ }
+
+ /**
+ * Sets state to determine if the any policy OID should be processed if it
+ * is included in a certificate. By default, the any policy OID is not
+ * inhibited ({@link #isAnyPolicyInhibited()} returns false).
+ *
+ * @return val - <code>true</code> if the any policy OID is to be
+ * inhibited, <code>false</code> otherwise
+ */
+ public void setAnyPolicyInhibited(boolean val)
+ {
+ anyPolicyInhibited = val;
+ }
+
+ /**
+ * Checks whether the any policy OID should be processed if it is included
+ * in a certificate.
+ *
+ * @return <code>true</code> if the any policy OID is inhibited,
+ * <code>false</code> otherwise
+ */
+ public boolean isAnyPolicyInhibited()
+ {
+ return anyPolicyInhibited;
+ }
+
+ /**
+ * Sets the PolicyQualifiersRejected flag. If this flag is true,
+ * certificates that include policy qualifiers in a certificate policies
+ * extension that is marked critical are rejected. If the flag is false,
+ * certificates are not rejected on this basis.<br />
+ * <br />
+ * When a <code>PKIXParameters</code> object is created, this flag is set
+ * to true. This setting reflects the most common (and simplest) strategy
+ * for processing policy qualifiers. Applications that want to use a more
+ * sophisticated policy must set this flag to false.<br />
+ * <br />
+ * Note that the PKIX certification path validation algorithm specifies that
+ * any policy qualifier in a certificate policies extension that is marked
+ * critical must be processed and validated. Otherwise the certification
+ * path must be rejected. If the policyQualifiersRejected flag is set to
+ * false, it is up to the application to validate all policy qualifiers in
+ * this manner in order to be PKIX compliant.
+ *
+ * @param qualifiersRejected
+ * the new value of the PolicyQualifiersRejected flag
+ *
+ * @see #getPolicyQualifiersRejected()
+ * @see PolicyQualifierInfo
+ */
+ public void setPolicyQualifiersRejected(boolean qualifiersRejected)
+ {
+ policyQualifiersRejected = qualifiersRejected;
+ }
+
+ /**
+ * Gets the PolicyQualifiersRejected flag. If this flag is true,
+ * certificates that include policy qualifiers in a certificate policies
+ * extension that is marked critical are rejected. If the flag is false,
+ * certificates are not rejected on this basis.<br />
+ * <br />
+ * When a PKIXParameters object is created, this flag is set to true. This
+ * setting reflects the most common (and simplest) strategy for processing
+ * policy qualifiers. Applications that want to use a more sophisticated
+ * policy must set this flag to false.
+ *
+ * @return the current value of the PolicyQualifiersRejected flag
+ *
+ * @see #setPolicyQualifiersRejected(boolean)
+ */
+ public boolean getPolicyQualifiersRejected()
+ {
+ return policyQualifiersRejected;
+ }
+
+ /**
+ * Returns the time for which the validity of the certification path should
+ * be determined. If null, the current time is used.<br />
+ * <br />
+ * Note that the Date returned is copied to protect against subsequent
+ * modifications.
+ *
+ * @return the Date, or <code>null</code> if not set
+ *
+ * @see #setDate(java.util.Date)
+ */
+ public Date getDate()
+ {
+ if (date == null)
+ {
+ return null;
+ }
+
+ return new Date(date.getTime());
+ }
+
+ /**
+ * Sets the time for which the validity of the certification path should be
+ * determined. If null, the current time is used.<br />
+ * <br />
+ * Note that the Date supplied here is copied to protect against subsequent
+ * modifications.
+ *
+ * @param date
+ * the Date, or <code>null</code> for the current time
+ *
+ * @see #getDate()
+ */
+ public void setDate(Date date)
+ {
+ if (date == null)
+ {
+ this.date = null;
+ }
+ else
+ {
+ this.date = new Date(date.getTime());
+ }
+ }
+
+ /**
+ * Sets a <code>List</code> of additional certification path checkers. If
+ * the specified List contains an object that is not a PKIXCertPathChecker,
+ * it is ignored.<br />
+ * <br />
+ * Each <code>PKIXCertPathChecker</code> specified implements additional
+ * checks on a certificate. Typically, these are checks to process and
+ * verify private extensions contained in certificates. Each
+ * <code>PKIXCertPathChecker</code> should be instantiated with any
+ * initialization parameters needed to execute the check.<br />
+ * <br />
+ * This method allows sophisticated applications to extend a PKIX
+ * <code>CertPathValidator</code> or <code>CertPathBuilder</code>. Each
+ * of the specified PKIXCertPathCheckers will be called, in turn, by a PKIX
+ * <code>CertPathValidator</code> or <code>CertPathBuilder</code> for
+ * each certificate processed or validated.<br />
+ * <br />
+ * Regardless of whether these additional PKIXCertPathCheckers are set, a
+ * PKIX <code>CertPathValidator</code> or <code>CertPathBuilder</code>
+ * must perform all of the required PKIX checks on each certificate. The one
+ * exception to this rule is if the RevocationEnabled flag is set to false
+ * (see the {@link #setRevocationEnabled(boolean) setRevocationEnabled}
+ * method).<br />
+ * <br />
+ * Note that the List supplied here is copied and each PKIXCertPathChecker
+ * in the list is cloned to protect against subsequent modifications.
+ *
+ * @param checkers
+ * a List of PKIXCertPathCheckers. May be null, in which case no
+ * additional checkers will be used.
+ * @exception ClassCastException
+ * if any of the elements in the list are not of type
+ * <code>java.security.cert.PKIXCertPathChecker</code>
+ * @see #getCertPathCheckers()
+ */
+ public void setCertPathCheckers(List checkers)
+ {
+ certPathCheckers = new ArrayList();
+ if (checkers == null)
+ {
+ return;
+ }
+ Iterator iter = checkers.iterator();
+ while (iter.hasNext())
+ {
+ certPathCheckers
+ .add((PKIXCertPathChecker)((PKIXCertPathChecker)iter.next())
+ .clone());
+ }
+ }
+
+ /**
+ * Returns the List of certification path checkers. The returned List is
+ * immutable, and each PKIXCertPathChecker in the List is cloned to protect
+ * against subsequent modifications.
+ *
+ * @return an immutable List of PKIXCertPathCheckers (may be empty, but not
+ * <code>null</code>)
+ *
+ * @see #setCertPathCheckers(java.util.List)
+ */
+ public List getCertPathCheckers()
+ {
+ List checkers = new ArrayList();
+ Iterator iter = certPathCheckers.iterator();
+ while (iter.hasNext())
+ {
+ checkers
+ .add((PKIXCertPathChecker)((PKIXCertPathChecker)iter.next())
+ .clone());
+ }
+ return Collections.unmodifiableList(checkers);
+ }
+
+ /**
+ * Adds a PKIXCertPathChecker to the list of certification path checkers.
+ * See the {@link #setCertPathCheckers} method for more details.<br />
+ * <br />
+ * Note that the <code>PKIXCertPathChecker</code> is cloned to protect
+ * against subsequent modifications.
+ *
+ * @param checker
+ * a <code>PKIXCertPathChecker</code> to add to the list of
+ * checks. If <code>null</code>, the checker is ignored (not
+ * added to list).
+ */
+ public void addCertPathChecker(PKIXCertPathChecker checker)
+ {
+ if (checker != null)
+ {
+ certPathCheckers.add(checker.clone());
+ }
+ }
+
+ /**
+ * Returns the signature provider's name, or <code>null</code> if not set.
+ *
+ * @return the signature provider's name (or <code>null</code>)
+ *
+ * @see #setSigProvider(java.lang.String)
+ */
+ public String getSigProvider()
+ {
+ return sigProvider;
+ }
+
+ /**
+ * Sets the signature provider's name. The specified provider will be
+ * preferred when creating Signature objects. If null or not set, the first
+ * provider found supporting the algorithm will be used.
+ *
+ * @param sigProvider
+ * the signature provider's name (or <code>null</code>)
+ *
+ * @see #getSigProvider()
+ */
+ public void setSigProvider(String sigProvider)
+ {
+ this.sigProvider = sigProvider;
+ }
+
+ /**
+ * Returns the required constraints on the target certificate. The
+ * constraints are returned as an instance of CertSelector. If
+ * <code>null</code>, no constraints are defined.<br />
+ * <br />
+ * Note that the CertSelector returned is cloned to protect against
+ * subsequent modifications.
+ *
+ * @return a CertSelector specifying the constraints on the target
+ * certificate (or <code>null</code>)
+ *
+ * @see #setTargetCertConstraints(CertSelector)
+ */
+ public CertSelector getTargetCertConstraints()
+ {
+ if (certSelector == null)
+ {
+ return null;
+ }
+
+ return (CertSelector)certSelector.clone();
+ }
+
+ /**
+ * Sets the required constraints on the target certificate. The constraints
+ * are specified as an instance of CertSelector. If null, no constraints are
+ * defined.<br />
+ * <br />
+ * Note that the CertSelector specified is cloned to protect against
+ * subsequent modifications.
+ *
+ * @param selector
+ * a CertSelector specifying the constraints on the target
+ * certificate (or <code>null</code>)
+ *
+ * @see #getTargetCertConstraints()
+ */
+ public void setTargetCertConstraints(CertSelector selector)
+ {
+ if (selector == null)
+ {
+ certSelector = null;
+ }
+ else
+ {
+ certSelector = (CertSelector)selector.clone();
+ }
+ }
+
+ /**
+ * Makes a copy of this PKIXParameters object. Changes to the copy will not
+ * affect the original and vice versa.
+ *
+ * @return a copy of this <code>PKIXParameters</code> object
+ */
+ public Object clone()
+ {
+ try
+ {
+ PKIXParameters obj = (PKIXParameters)super.clone();
+ obj.certStores = new ArrayList(certStores);
+ Iterator iter = certPathCheckers.iterator();
+ obj.certPathCheckers = new ArrayList();
+ while (iter.hasNext())
+ {
+ obj.certPathCheckers.add(((PKIXCertPathChecker)iter.next())
+ .clone());
+ }
+ if (initialPolicies != null)
+ {
+ obj.initialPolicies = new HashSet(initialPolicies);
+ }
+ if (trustAnchors != null)
+ {
+ obj.trustAnchors = new HashSet(trustAnchors);
+ }
+ if (certSelector != null)
+ {
+ obj.certSelector = (CertSelector)certSelector.clone();
+ }
+ return obj;
+ }
+ catch (CloneNotSupportedException ex)
+ {
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * Returns a formatted string describing the parameters.
+ *
+ * @return a formatted string describing the parameters.
+ */
+ public String toString()
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("[\n");
+ if (trustAnchors != null)
+ {
+ s.append(" Trust Anchors: ").append(trustAnchors).append('\n');
+ }
+ if (initialPolicies != null)
+ {
+ if (initialPolicies.isEmpty())
+ {
+ s.append(" Initial Policy OIDs: any\n");
+ }
+ else
+ {
+ s.append(" Initial Policy OIDs: [")
+ .append(initialPolicies).append("]\n");
+ }
+ }
+ s.append(" Validity Date: ");
+ if (date != null)
+ {
+ s.append(date);
+ }
+ else
+ {
+ s.append("null");
+ }
+ s.append('\n');
+
+ s.append(" Signature Provider: ");
+ if (sigProvider != null)
+ {
+ s.append(sigProvider);
+ }
+ else
+ {
+ s.append("null");
+ }
+ s.append('\n');
+
+ s.append(" Default Revocation Enabled: ");
+ s.append(revocationEnabled);
+ s.append('\n');
+
+ s.append(" Explicit Policy Required: ");
+ s.append(explicitPolicyRequired);
+ s.append('\n');
+
+ s.append(" Policy Mapping Inhibited: ");
+ s.append(policyMappingInhibited);
+ s.append('\n');
+
+ s.append(" Any Policy Inhibited: ");
+ s.append(anyPolicyInhibited);
+ s.append('\n');
+
+ s.append(" Policy Qualifiers Rejected: ");
+ s.append(policyQualifiersRejected);
+ s.append('\n');
+
+ s.append(" Target Cert Constraints: ");
+ s.append(certSelector);
+ s.append('\n');
+
+ s.append(" Certification Path Checkers: [");
+ s.append(certPathCheckers);
+ s.append("}\n");
+
+ s.append(" CertStores: [");
+ s.append(certStores);
+ s.append("}\n");
+
+ s.append("]\n");
+
+ return s.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java
new file mode 100644
index 000000000..ae9199b37
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java
@@ -0,0 +1,107 @@
+package org.spongycastle.jce.cert;
+
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * An immutable valid policy tree node as defined by the PKIX certification
+ * path validation algorithm.<br />
+ * <br />
+ * One of the outputs of the PKIX certification path validation
+ * algorithm is a valid policy tree, which includes the policies that
+ * were determined to be valid, how this determination was reached,
+ * and any policy qualifiers encountered. This tree is of depth
+ * <i>n</i>, where <i>n</i> is the length of the certification
+ * path that has been validated.<br />
+ * <br />
+ * Most applications will not need to examine the valid policy tree.
+ * They can achieve their policy processing goals by setting the
+ * policy-related parameters in <code>PKIXParameters</code>. However,
+ * the valid policy tree is available for more sophisticated applications,
+ * especially those that process policy qualifiers.<br />
+ * <br />
+ * {@link PKIXCertPathValidatorResult#getPolicyTree()
+ * PKIXCertPathValidatorResult.getPolicyTree} returns the root node of the
+ * valid policy tree. The tree can be traversed using the
+ * {@link #getChildren getChildren} and {@link #getParent getParent} methods.
+ * Data about a particular node can be retrieved using other methods of
+ * <code>PolicyNode</code>.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * All <code>PolicyNode</code> objects must be immutable and
+ * thread-safe. Multiple threads may concurrently invoke the methods defined
+ * in this class on a single <code>PolicyNode</code> object (or more than one)
+ * with no ill effects. This stipulation applies to all public fields and
+ * methods of this class and any added or overridden by subclasses.
+ **/
+public interface PolicyNode
+{
+
+ /**
+ * Returns the parent of this node, or <code>null</code> if this is the
+ * root node.
+ *
+ * @return the parent of this node, or <code>null</code> if this is the
+ * root node
+ */
+ public PolicyNode getParent();
+
+ /**
+ * Returns an iterator over the children of this node. Any attempts to
+ * modify the children of this node through the
+ * <code>Iterator</code>'s remove method must throw an
+ * <code>UnsupportedOperationException</code>.
+ *
+ * @return an iterator over the children of this node
+ */
+ public Iterator getChildren();
+
+ /**
+ * Returns the depth of this node in the valid policy tree.
+ *
+ * @return the depth of this node (0 for the root node, 1 for its
+ * children, and so on)
+ */
+ public int getDepth();
+
+ /**
+ * Returns the valid policy represented by this node.
+ *
+ * @return the <code>String</code> OID of the valid policy
+ * represented by this node, or the special value "any-policy". For
+ * the root node, this method always returns the special value "any-policy".
+ */
+ public String getValidPolicy();
+
+ /**
+ * Returns the set of policy qualifiers associated with the
+ * valid policy represented by this node.
+ *
+ * @return an immutable <code>Set</code> of
+ * <code>PolicyQualifierInfo</code>s. For the root node, this
+ * is always an empty <code>Set</code>.
+ */
+ public Set getPolicyQualifiers();
+
+ /**
+ * Returns the set of expected policies that would satisfy this
+ * node's valid policy in the next certificate to be processed.
+ *
+ * @return an immutable <code>Set</code> of expected policy
+ * <code>String</code> OIDs, or an immutable <code>Set</code> with
+ * the single special value "any-policy". For the root node, this method
+ * always returns a <code>Set</code> with the single value "any-policy".
+ */
+ public Set getExpectedPolicies();
+
+ /**
+ * Returns the criticality indicator of the certificate policy extension
+ * in the most recently processed certificate.
+ *
+ * @return <code>true</code> if extension marked critical,
+ * <code>false</code> otherwise. For the root node, <code>false</code>
+ * is always returned.
+ */
+ public boolean isCritical();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java
new file mode 100644
index 000000000..97e9c5faa
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java
@@ -0,0 +1,196 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.util.ASN1Dump;
+
+/**
+ * An immutable policy qualifier represented by the ASN.1 PolicyQualifierInfo
+ * structure.<br />
+ * <br />
+ * The ASN.1 definition is as follows:<br />
+ * <br />
+ *
+ * <pre>
+ * PolicyQualifierInfo ::= SEQUENCE {
+ * policyQualifierId PolicyQualifierId,
+ * qualifier ANY DEFINED BY policyQualifierId }
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * A certificate policies extension, if present in an X.509 version 3
+ * certificate, contains a sequence of one or more policy information terms,
+ * each of which consists of an object identifier (OID) and optional qualifiers.
+ * In an end-entity certificate, these policy information terms indicate the
+ * policy under which the certificate has been issued and the purposes for which
+ * the certificate may be used. In a CA certificate, these policy information
+ * terms limit the set of policies for certification paths which include this
+ * certificate.<br />
+ * <br />
+ * A <code>Set</code> of <code>PolicyQualifierInfo</code> objects are
+ * returned by the
+ * {@link PolicyNode#getPolicyQualifiers PolicyNode.getPolicyQualifiers} method.
+ * This allows applications with specific policy requirements to process and
+ * validate each policy qualifier. Applications that need to process policy
+ * qualifiers should explicitly set the <code>policyQualifiersRejected</code>
+ * flag to false (by calling the
+ * {@link PKIXParameters#setPolicyQualifiersRejected
+ * PKIXParameters.setPolicyQualifiersRejected} method) before validating a
+ * certification path.<br />
+ * <br />
+ * Note that the PKIX certification path validation algorithm specifies that any
+ * policy qualifier in a certificate policies extension that is marked critical
+ * must be processed and validated. Otherwise the certification path must be
+ * rejected. If the <code>policyQualifiersRejected</code> flag is set to
+ * false, it is up to the application to validate all policy qualifiers in this
+ * manner in order to be PKIX compliant.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * All <code>PolicyQualifierInfo</code> objects must be immutable and
+ * thread-safe. That is, multiple threads may concurrently invoke the methods
+ * defined in this class on a single <code>PolicyQualifierInfo</code> object
+ * (or more than one) with no ill effects. Requiring
+ * <code>PolicyQualifierInfo</code> objects to be immutable and thread-safe
+ * allows them to be passed around to various pieces of code without worrying
+ * about coordinating access.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object}
+ */
+public final class PolicyQualifierInfo
+{
+ private String id;
+
+ private byte[] encoded;
+
+ private byte[] qualifier;
+
+ /**
+ * Creates an instance of <code>PolicyQualifierInfo</code> from the
+ * encoded bytes. The encoded byte array is copied on construction.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier} and
+ * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream}
+ *
+ * @param encoded
+ * a byte array containing the qualifier in DER encoding
+ *
+ * @exception IOException
+ * thrown if the byte array does not represent a valid and
+ * parsable policy qualifier
+ */
+ public PolicyQualifierInfo(byte[] encoded) throws IOException
+ {
+ this.encoded = (byte[])encoded.clone();
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ this.encoded);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Sequence obj = (ASN1Sequence)derInStream.readObject();
+ id = ((ASN1ObjectIdentifier)obj.getObjectAt(0)).getId();
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DEROutputStream derOutStream = new DEROutputStream(outStream);
+
+ derOutStream.writeObject(obj.getObjectAt(1));
+ derOutStream.close();
+
+ qualifier = outStream.toByteArray();
+ }
+ catch (Exception ex)
+ {
+ throw new IOException("parsing exception : " + ex.toString());
+ }
+ }
+
+ /**
+ * Returns the <code>policyQualifierId</code> field of this
+ * <code>PolicyQualifierInfo</code>. The <code>policyQualifierId</code>
+ * is an Object Identifier (OID) represented by a set of nonnegative
+ * integers separated by periods.
+ *
+ * @return the OID (never <code>null</code>)
+ */
+ public String getPolicyQualifierId()
+ {
+ return id;
+ }
+
+ /**
+ * Returns the ASN.1 DER encoded form of this
+ * <code>PolicyQualifierInfo</code>.
+ *
+ * @return the ASN.1 DER encoded bytes (never <code>null</code>). Note
+ * that a copy is returned, so the data is cloned each time this
+ * method is called.
+ */
+ public byte[] getEncoded()
+ {
+ return (byte[])encoded.clone();
+ }
+
+ /**
+ * Returns the ASN.1 DER encoded form of the <code>qualifier</code> field
+ * of this <code>PolicyQualifierInfo</code>.
+ *
+ * @return the ASN.1 DER encoded bytes of the <code>qualifier</code>
+ * field. Note that a copy is returned, so the data is cloned each
+ * time this method is called.
+ */
+ public byte[] getPolicyQualifier()
+ {
+ if (qualifier == null)
+ {
+ return null;
+ }
+
+ return (byte[])qualifier.clone();
+ }
+
+ /**
+ * Return a printable representation of this
+ * <code>PolicyQualifierInfo</code>.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object}
+ *
+ * @return a <code>String</code> describing the contents of this
+ * <code>PolicyQualifierInfo</code>
+ */
+ public String toString()
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("PolicyQualifierInfo: [\n");
+ s.append("qualifierID: ").append(id).append('\n');
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(qualifier);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object derObject = derInStream.readObject();
+ s
+ .append(" qualifier:\n").append(ASN1Dump.dumpAsString(derObject))
+ .append('\n');
+ }
+ catch (IOException ex)
+ {
+ s.append(ex.getMessage());
+ }
+ s.append("qualifier: ").append(id).append('\n');
+ s.append(']');
+ return s.toString();
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java
new file mode 100644
index 000000000..68a9abf3d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java
@@ -0,0 +1,293 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1Sequence;
+
+/**
+ * A trust anchor or most-trusted Certification Authority (CA). <br />
+ * <br />
+ * This class represents a "most-trusted CA", which is used as a trust anchor
+ * for validating X.509 certification paths. A most-trusted CA includes the
+ * public key of the CA, the CA's name, and any constraints upon the set of
+ * paths which may be validated using this key. These parameters can be
+ * specified in the form of a trusted X509Certificate or as individual
+ * parameters. <br />
+ * <br />
+ * <strong>Concurrent Access</strong><br />
+ * <br />
+ * All TrustAnchor objects must be immutable and thread-safe. That is, multiple
+ * threads may concurrently invoke the methods defined in this class on a
+ * single TrustAnchor object (or more than one) with no ill effects. Requiring
+ * TrustAnchor objects to be immutable and thread-safe allows them to be passed
+ * around to various pieces of code without worrying about coordinating access.
+ * This stipulation applies to all public fields and methods of this class and
+ * any added or overridden by subclasses.<br />
+ * <br />
+ * <b>TODO: implement better nameConstraints testing.</b>
+ **/
+public class TrustAnchor
+{
+ private X509Certificate trustCert = null;
+
+ private PublicKey trustPublicKey = null;
+
+ private String trustName = null;
+
+ private byte[] nameConstraints = null;
+
+ /**
+ * Creates an instance of TrustAnchor with the specified X509Certificate and
+ * optional name constraints, which are intended to be used as additional
+ * constraints when validating an X.509 certification path.<br />
+ * <br />
+ * The name constraints are specified as a byte array. This byte array
+ * should contain the DER encoded form of the name constraints, as they
+ * would appear in the NameConstraints structure defined in RFC 2459 and
+ * X.509. The ASN.1 definition of this structure appears below.<br />
+ * <br />
+ *
+ * <pre>
+ * NameConstraints ::= SEQUENCE {
+ * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ *
+ * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ *
+ * GeneralSubtree ::= SEQUENCE {
+ * base GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL }
+ *
+ * BaseDistance ::= INTEGER (0..MAX)
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * Note that the name constraints byte array supplied is cloned to protect
+ * against subsequent modifications.
+ *
+ * @param trustedCert
+ * a trusted X509Certificate
+ * @param nameConstraints
+ * a byte array containing the ASN.1 DER encoding of a
+ * NameConstraints extension to be used for checking name
+ * constraints. Only the value of the extension is included, not
+ * the OID or criticality flag. Specify null to omit the
+ * parameter.
+ *
+ * @exception IllegalArgumentException
+ * if the name constraints cannot be decoded
+ * @exception NullPointerException
+ * if the specified X509Certificate is null
+ */
+ public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints)
+ {
+ if (trustedCert == null)
+ {
+ throw new NullPointerException("trustedCert must be non-null");
+ }
+
+ this.trustCert = trustedCert;
+ if (nameConstraints != null)
+ {
+ this.nameConstraints = (byte[])nameConstraints.clone();
+ checkNameConstraints(this.nameConstraints);
+ }
+ }
+
+ /**
+ * Creates an instance of <code>TrustAnchor</code> where the most-trusted
+ * CA is specified as a distinguished name and public key. Name constraints
+ * are an optional parameter, and are intended to be used as additional
+ * constraints when validating an X.509 certification path.
+ *
+ * The name constraints are specified as a byte array. This byte array
+ * contains the DER encoded form of the name constraints, as they would
+ * appear in the NameConstraints structure defined in RFC 2459 and X.509.
+ * The ASN.1 notation for this structure is supplied in the documentation
+ * for {@link #TrustAnchor(X509Certificate trustedCert, byte[]
+ * nameConstraints) TrustAnchor(X509Certificate trustedCert, byte[]
+ * nameConstraints) }.
+ *
+ * Note that the name constraints byte array supplied here is cloned to
+ * protect against subsequent modifications.
+ *
+ * @param caName
+ * the X.500 distinguished name of the most-trusted CA in RFC
+ * 2253 String format
+ * @param pubKey
+ * the public key of the most-trusted CA
+ * @param nameConstraints
+ * a byte array containing the ASN.1 DER encoding of a
+ * NameConstraints extension to be used for checking name
+ * constraints. Only the value of the extension is included, not
+ * the OID or criticality flag. Specify null to omit the
+ * parameter.
+ *
+ * @exception IllegalArgumentException
+ * if the specified caName parameter is empty (<code>caName.length() == 0</code>)
+ * or incorrectly formatted or the name constraints cannot be
+ * decoded
+ * @exception NullPointerException
+ * if the specified caName or pubKey parameter is null
+ */
+ public TrustAnchor(String caName, PublicKey pubKey, byte[] nameConstraints)
+ {
+ if (caName == null)
+ {
+ throw new NullPointerException("caName must be non-null");
+ }
+ if (pubKey == null)
+ {
+ throw new NullPointerException("pubKey must be non-null");
+ }
+ if (caName.length() == 0)
+ {
+ throw new IllegalArgumentException(
+ "caName can not be an empty string");
+ }
+
+ this.trustName = caName;
+ this.trustPublicKey = pubKey;
+ if (nameConstraints != null)
+ {
+ this.nameConstraints = (byte[])nameConstraints.clone();
+ checkNameConstraints(this.nameConstraints);
+ }
+ }
+
+ /**
+ * Returns the most-trusted CA certificate.
+ *
+ * @return a trusted <code>X509Certificate</code> or <code>null</code>
+ * if the trust anchor was not specified as a trusted certificate
+ */
+ public final X509Certificate getTrustedCert()
+ {
+ return trustCert;
+ }
+
+ /**
+ * Returns the name of the most-trusted CA in RFC 2253 String format.
+ *
+ * @return the X.500 distinguished name of the most-trusted CA, or
+ * <code>null</code> if the trust anchor was not specified as a
+ * trusted public key and name pair
+ */
+ public final String getCAName()
+ {
+ return trustName;
+ }
+
+ /**
+ * Returns the public key of the most-trusted CA.
+ *
+ * @return the public key of the most-trusted CA, or null if the trust
+ * anchor was not specified as a trusted public key and name pair
+ */
+ public final PublicKey getCAPublicKey()
+ {
+ return trustPublicKey;
+ }
+
+ /**
+ * Returns the name constraints parameter. The specified name constraints
+ * are associated with this trust anchor and are intended to be used as
+ * additional constraints when validating an X.509 certification path.<br />
+ * <br />
+ * The name constraints are returned as a byte array. This byte array
+ * contains the DER encoded form of the name constraints, as they would
+ * appear in the NameConstraints structure defined in RFC 2459 and X.509.
+ * The ASN.1 notation for this structure is supplied in the documentation
+ * for <code>TrustAnchor(X509Certificate trustedCert, byte[]
+ * nameConstraints)</code>.<br />
+ * <br />
+ * Note that the byte array returned is cloned to protect against subsequent
+ * modifications.
+ *
+ * @return a byte array containing the ASN.1 DER encoding of a
+ * NameConstraints extension used for checking name constraints, or
+ * <code>null</code> if not set.
+ */
+ public final byte[] getNameConstraints()
+ {
+ return (byte[])nameConstraints.clone();
+ }
+
+ /**
+ * Returns a formatted string describing the <code>TrustAnchor</code>.
+ *
+ * @return a formatted string describing the <code>TrustAnchor</code>
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("[\n");
+ if (getCAPublicKey() != null)
+ {
+ sb.append(" Trusted CA Public Key: ").append(getCAPublicKey()).append('\n');
+ sb.append(" Trusted CA Issuer Name: ").append(getCAName()).append('\n');
+ }
+ else
+ {
+ sb.append(" Trusted CA cert: ").append(getTrustedCert()).append('\n');
+ }
+ if (nameConstraints != null)
+ {
+ sb.append(" Name Constraints: ").append(nameConstraints).append('\n');
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Check given DER encoded nameConstraints for correct decoding. Currently
+ * only basic DER decoding test.<br />
+ * <br />
+ * <b>TODO: implement more testing.</b>
+ *
+ * @param data
+ * the DER encoded nameConstrains to be checked or
+ * <code>null</code>
+ * @exception IllegalArgumentException
+ * if the check failed.
+ */
+ private void checkNameConstraints(byte[] data)
+ {
+ if (data != null)
+ {
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(data);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object derObject = derInStream.readObject();
+ if (!(derObject instanceof ASN1Sequence))
+ {
+ throw new IllegalArgumentException(
+ "nameConstraints parameter decoding error");
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException(
+ "nameConstraints parameter decoding error: " + ex);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java
new file mode 100644
index 000000000..6ddd43356
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java
@@ -0,0 +1,717 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRL;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.PrincipalUtil;
+
+/**
+ * A <code>CRLSelector</code> that selects <code>X509CRLs</code> that match
+ * all specified criteria. This class is particularly useful when selecting CRLs
+ * from a <code>CertStore</code> to check revocation status of a particular
+ * certificate.<br />
+ * <br />
+ * When first constructed, an <code>X509CRLSelector</code> has no criteria
+ * enabled and each of the <code>get</code> methods return a default value (<code>null</code>).
+ * Therefore, the {@link #match match} method would return <code>true</code>
+ * for any <code>X509CRL</code>. Typically, several criteria are enabled (by
+ * calling {@link #setIssuerNames setIssuerNames} or
+ * {@link #setDateAndTime setDateAndTime}, for instance) and then the
+ * <code>X509CRLSelector</code> is passed to
+ * {@link CertStore#getCRLs CertStore.getCRLs} or some similar method.<br />
+ * <br />
+ * Please refer to RFC 2459 for definitions of the X.509 CRL fields and
+ * extensions mentioned below.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single object
+ * concurrently should synchronize amongst themselves and provide the necessary
+ * locking. Multiple threads each manipulating separate objects need not
+ * synchronize.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name}
+ *
+ * @see CRLSelector
+ * @see X509CRL
+ */
+public class X509CRLSelector implements CRLSelector
+{
+ private Set issuerNames = null;
+
+ private Set issuerNamesX509 = null;
+
+ private BigInteger minCRL = null;
+
+ private BigInteger maxCRL = null;
+
+ private Date dateAndTime = null;
+
+ private X509Certificate certChecking = null;
+
+ /**
+ * Creates an <code>X509CRLSelector</code>. Initially, no criteria are
+ * set so any <code>X509CRL</code> will match.
+ */
+ public X509CRLSelector()
+ {
+ }
+
+ /**
+ * Sets the issuerNames criterion. The issuer distinguished name in the
+ * <code>X509CRL</code> must match at least one of the specified
+ * distinguished names. If <code>null</code>, any issuer distinguished
+ * name will do.<br />
+ * <br />
+ * This method allows the caller to specify, with a single method call, the
+ * complete set of issuer names which <code>X509CRLs</code> may contain.
+ * The specified value replaces the previous value for the issuerNames
+ * criterion.<br />
+ * <br />
+ * The <code>names</code> parameter (if not <code>null</code>) is a
+ * <code>Collection</code> of names. Each name is a <code>String</code>
+ * or a byte array representing a distinguished name (in RFC 2253 or ASN.1
+ * DER encoded form, respectively). If <code>null</code> is supplied as
+ * the value for this argument, no issuerNames check will be performed.<br />
+ * <br />
+ * Note that the <code>names</code> parameter can contain duplicate
+ * distinguished names, but they may be removed from the
+ * <code>Collection</code> of names returned by the
+ * {@link #getIssuerNames getIssuerNames} method.<br />
+ * <br />
+ * If a name is specified as a byte array, it should contain a single DER
+ * encoded distinguished name, as defined in X.501. The ASN.1 notation for
+ * this structure is as follows.
+ *
+ * <pre><code>
+ * Name ::= CHOICE {
+ * RDNSequence }
+ *
+ * RDNSequence ::= SEQUENCE OF RDN
+ *
+ * RDN ::=
+ * SET SIZE (1 .. MAX) OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ * ....
+ * DirectoryString ::= CHOICE {
+ * teletexString TeletexString (SIZE (1..MAX)),
+ * printableString PrintableString (SIZE (1..MAX)),
+ * universalString UniversalString (SIZE (1..MAX)),
+ * utf8String UTF8String (SIZE (1.. MAX)),
+ * bmpString BMPString (SIZE (1..MAX)) }
+ * </code></pre>
+ *
+ * <br />
+ * <br />
+ * Note that a deep copy is performed on the <code>Collection</code> to
+ * protect against subsequent modifications.
+ *
+ * @param names
+ * a <code>Collection</code> of names (or <code>null</code>)
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ *
+ * @see #getIssuerNames
+ */
+ public void setIssuerNames(Collection names) throws IOException
+ {
+ if (names == null || names.isEmpty())
+ {
+ issuerNames = null;
+ issuerNamesX509 = null;
+ }
+ else
+ {
+ Object item;
+ Iterator iter = names.iterator();
+ while (iter.hasNext())
+ {
+ item = iter.next();
+ if (item instanceof String)
+ {
+ addIssuerName((String)item);
+ }
+ else if (item instanceof byte[])
+ {
+ addIssuerName((byte[])item);
+ }
+ else
+ {
+ throw new IOException("name not byte[]or String: "
+ + item.toString());
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a name to the issuerNames criterion. The issuer distinguished name
+ * in the <code>X509CRL</code> must match at least one of the specified
+ * distinguished names.<br />
+ * <br />
+ * This method allows the caller to add a name to the set of issuer names
+ * which <code>X509CRLs</code> may contain. The specified name is added to
+ * any previous value for the issuerNames criterion. If the specified name
+ * is a duplicate, it may be ignored.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for parsing the
+ * name
+ *
+ * @param name
+ * the name in RFC 2253 form
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ */
+ public void addIssuerName(String name) throws IOException
+ {
+ if (issuerNames == null)
+ {
+ issuerNames = new HashSet();
+ issuerNamesX509 = new HashSet();
+ }
+ X509Name nameX509;
+ try
+ {
+ nameX509 = new X509Name(name);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new IOException(ex.getMessage());
+ }
+ issuerNamesX509.add(nameX509);
+ issuerNames.add(name);
+ }
+
+ /**
+ * Adds a name to the issuerNames criterion. The issuer distinguished name
+ * in the <code>X509CRL</code> must match at least one of the specified
+ * distinguished names.<br />
+ * <br />
+ * This method allows the caller to add a name to the set of issuer names
+ * which <code>X509CRLs</code> may contain. The specified name is added to
+ * any previous value for the issuerNames criterion. If the specified name
+ * is a duplicate, it may be ignored. If a name is specified as a byte
+ * array, it should contain a single DER encoded distinguished name, as
+ * defined in X.501. The ASN.1 notation for this structure is as follows.<br />
+ * <br />
+ * The name is provided as a byte array. This byte array should contain a
+ * single DER encoded distinguished name, as defined in X.501. The ASN.1
+ * notation for this structure appears in the documentation for
+ * {@link #setIssuerNames setIssuerNames(Collection names)}.<br />
+ * <br />
+ * Note that the byte array supplied here is cloned to protect against
+ * subsequent modifications.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for parsing the
+ * name, {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object} and
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence}
+ *
+ * @param name
+ * a byte array containing the name in ASN.1 DER encoded form
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ */
+ public void addIssuerName(byte[] name) throws IOException
+ {
+ if (issuerNames == null)
+ {
+ issuerNames = new HashSet();
+ issuerNamesX509 = new HashSet();
+ }
+
+ ByteArrayInputStream inStream = new ByteArrayInputStream(name);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object obj = derInStream.readObject();
+ if (obj instanceof ASN1Sequence)
+ {
+ issuerNamesX509.add(new X509Name((ASN1Sequence)obj));
+ }
+ else
+ {
+ throw new IOException("parsing error");
+ }
+ issuerNames.add(name.clone());
+ }
+
+ /**
+ * Sets the minCRLNumber criterion. The <code>X509CRL</code> must have a
+ * CRL number extension whose value is greater than or equal to the
+ * specified value. If <code>null</code>, no minCRLNumber check will be
+ * done.
+ *
+ * @param minCRL
+ * the minimum CRL number accepted (or <code>null</code>)
+ */
+ public void setMinCRLNumber(BigInteger minCRL)
+ {
+ this.minCRL = minCRL;
+ }
+
+ /**
+ * Sets the maxCRLNumber criterion. The <code>X509CRL</code> must have a
+ * CRL number extension whose value is less than or equal to the specified
+ * value. If <code>null</code>, no maxCRLNumber check will be done.
+ *
+ * @param maxCRL
+ * the maximum CRL number accepted (or <code>null</code>)
+ */
+ public void setMaxCRLNumber(BigInteger maxCRL)
+ {
+ this.maxCRL = maxCRL;
+ }
+
+ /**
+ * Sets the dateAndTime criterion. The specified date must be equal to or
+ * later than the value of the thisUpdate component of the
+ * <code>X509CRL</code> and earlier than the value of the nextUpdate
+ * component. There is no match if the <code>X509CRL</code> does not
+ * contain a nextUpdate component. If <code>null</code>, no dateAndTime
+ * check will be done.<br />
+ * <br />
+ * Note that the <code>Date</code> supplied here is cloned to protect
+ * against subsequent modifications.
+ *
+ * @param dateAndTime
+ * the <code>Date</code> to match against (or <code>null</code>)
+ *
+ * @see #getDateAndTime
+ */
+ public void setDateAndTime(Date dateAndTime)
+ {
+ if (dateAndTime == null)
+ {
+ this.dateAndTime = null;
+ }
+ else
+ {
+ this.dateAndTime = new Date(dateAndTime.getTime());
+ }
+ }
+
+ /**
+ * Sets the certificate being checked. This is not a criterion. Rather, it
+ * is optional information that may help a <code>CertStore</code> find
+ * CRLs that would be relevant when checking revocation for the specified
+ * certificate. If <code>null</code> is specified, then no such optional
+ * information is provided.
+ *
+ * @param cert
+ * the <code>X509Certificate</code> being checked (or
+ * <code>null</code>)
+ *
+ * @see #getCertificateChecking
+ */
+ public void setCertificateChecking(X509Certificate cert)
+ {
+ certChecking = cert;
+ }
+
+ /**
+ * Returns a copy of the issuerNames criterion. The issuer distinguished
+ * name in the <code>X509CRL</code> must match at least one of the
+ * specified distinguished names. If the value returned is <code>null</code>,
+ * any issuer distinguished name will do.<br />
+ * <br />
+ * If the value returned is not <code>null</code>, it is a
+ * <code>Collection</code> of names. Each name is a <code>String</code>
+ * or a byte array representing a distinguished name (in RFC 2253 or ASN.1
+ * DER encoded form, respectively). Note that the <code>Collection</code>
+ * returned may contain duplicate names.<br />
+ * <br />
+ * If a name is specified as a byte array, it should contain a single DER
+ * encoded distinguished name, as defined in X.501. The ASN.1 notation for
+ * this structure is given in the documentation for
+ * {@link #setIssuerNames setIssuerNames(Collection names)}.<br />
+ * <br />
+ * Note that a deep copy is performed on the <code>Collection</code> to
+ * protect against subsequent modifications.
+ *
+ * @return a <code>Collection</code> of names (or <code>null</code>)
+ * @see #setIssuerNames
+ */
+ public Collection getIssuerNames()
+ {
+ if (issuerNames == null)
+ {
+ return null;
+ }
+
+ Collection set = new HashSet();
+ Iterator iter = issuerNames.iterator();
+ Object item;
+ while (iter.hasNext())
+ {
+ item = iter.next();
+ if (item instanceof String)
+ {
+ set.add(new String((String)item));
+ }
+ else if (item instanceof byte[])
+ {
+ set.add(((byte[])item).clone());
+ }
+ }
+ return set;
+ }
+
+ /**
+ * Returns the minCRLNumber criterion. The <code>X509CRL</code> must have
+ * a CRL number extension whose value is greater than or equal to the
+ * specified value. If <code>null</code>, no minCRLNumber check will be
+ * done.
+ *
+ * @return the minimum CRL number accepted (or <code>null</code>)
+ */
+ public BigInteger getMinCRL()
+ {
+ return minCRL;
+ }
+
+ /**
+ * Returns the maxCRLNumber criterion. The <code>X509CRL</code> must have
+ * a CRL number extension whose value is less than or equal to the specified
+ * value. If <code>null</code>, no maxCRLNumber check will be done.
+ *
+ * @return the maximum CRL number accepted (or <code>null</code>)
+ */
+ public BigInteger getMaxCRL()
+ {
+ return maxCRL;
+ }
+
+ /**
+ * Returns the dateAndTime criterion. The specified date must be equal to or
+ * later than the value of the thisUpdate component of the
+ * <code>X509CRL</code> and earlier than the value of the nextUpdate
+ * component. There is no match if the <code>X509CRL</code> does not
+ * contain a nextUpdate component. If <code>null</code>, no dateAndTime
+ * check will be done.<br />
+ * <br />
+ * Note that the <code>Date</code> returned is cloned to protect against
+ * subsequent modifications.
+ *
+ * @return the <code>Date</code> to match against (or <code>null</code>)
+ *
+ * @see #setDateAndTime
+ */
+ public Date getDateAndTime()
+ {
+ if (dateAndTime == null)
+ {
+ return null;
+ }
+
+ return new Date(dateAndTime.getTime());
+ }
+
+ /**
+ * Returns the certificate being checked. This is not a criterion. Rather,
+ * it is optional information that may help a <code>CertStore</code> find
+ * CRLs that would be relevant when checking revocation for the specified
+ * certificate. If the value returned is <code>null</code>, then no such
+ * optional information is provided.
+ *
+ * @return the certificate being checked (or <code>null</code>)
+ *
+ * @see #setCertificateChecking
+ */
+ public X509Certificate getCertificateChecking()
+ {
+ return certChecking;
+ }
+
+ /**
+ * Returns a printable representation of the <code>X509CRLSelector</code>.<br />
+ * <br />
+ * Uses
+ * {@link org.spongycastle.asn1.x509.X509Name#toString X509Name.toString} to
+ * format the output
+ *
+ * @return a <code>String</code> describing the contents of the
+ * <code>X509CRLSelector</code>.
+ */
+ public String toString()
+ {
+ StringBuffer s = new StringBuffer();
+ s.append("X509CRLSelector: [\n");
+ if (issuerNamesX509 != null)
+ {
+ s.append(" IssuerNames:\n");
+ Iterator iter = issuerNamesX509.iterator();
+ while (iter.hasNext())
+ {
+ s.append(" ").append(iter.next()).append('\n');
+ }
+ }
+ if (minCRL != null)
+ {
+ s.append(" minCRLNumber: ").append(minCRL).append('\n');
+ }
+ if (maxCRL != null)
+ {
+ s.append(" maxCRLNumber: ").append(maxCRL).append('\n');
+ }
+ if (dateAndTime != null)
+ {
+ s.append(" dateAndTime: ").append(dateAndTime).append('\n');
+ }
+ if (certChecking != null)
+ {
+ s.append(" Certificate being checked: ").append(certChecking).append('\n');
+ }
+ s.append(']');
+ return s.toString();
+ }
+
+ /**
+ * Decides whether a <code>CRL</code> should be selected.<br />
+ * <br />
+ * Uses
+ * {@link org.spongycastle.asn1.x509.X509Name#toString X509Name.toString} to
+ * parse and to compare the crl parameter issuer and
+ * {@link org.spongycastle.asn1.x509.X509Extensions#CRLNumber CRLNumber} to
+ * access the CRL number extension.
+ *
+ * @param crl
+ * the <code>CRL</code> to be checked
+ *
+ * @return <code>true</code> if the <code>CRL</code> should be selected,
+ * <code>false</code> otherwise
+ */
+ public boolean match(CRL crl)
+ {
+ if (!(crl instanceof X509CRL))
+ {
+ return false;
+ }
+
+ X509CRL crlX509 = (X509CRL)crl;
+ boolean test;
+
+ if (issuerNamesX509 != null)
+ {
+ Iterator iter = issuerNamesX509.iterator();
+ test = false;
+ X509Name crlIssuer = null;
+ try
+ {
+ crlIssuer = PrincipalUtil.getIssuerX509Principal(crlX509);
+ }
+ catch (Exception ex)
+ {
+
+ return false;
+ }
+
+ while (iter.hasNext())
+ {
+ if (crlIssuer.equals(iter.next(), true))
+ {
+ test = true;
+ break;
+ }
+ }
+ if (!test)
+ {
+ return false;
+ }
+ }
+
+ byte[] data = crlX509.getExtensionValue(X509Extensions.CRLNumber
+ .getId());
+ if (data != null)
+ {
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(data);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ inStream = new ByteArrayInputStream(
+ ((ASN1OctetString)derInputStream.readObject())
+ .getOctets());
+ derInputStream = new ASN1InputStream(inStream);
+ BigInteger crlNumber = ((DERInteger)derInputStream.readObject())
+ .getPositiveValue();
+ if (minCRL != null && minCRL.compareTo(crlNumber) > 0)
+ {
+ return false;
+ }
+ if (maxCRL != null && maxCRL.compareTo(crlNumber) < 0)
+ {
+ return false;
+ }
+ }
+ catch (IOException ex)
+ {
+ return false;
+ }
+ }
+ else if (minCRL != null || maxCRL != null)
+ {
+ return false;
+ }
+
+ if (dateAndTime != null)
+ {
+ Date check = crlX509.getThisUpdate();
+ if (check == null)
+ {
+ return false;
+ }
+ else if (dateAndTime.before(check))
+ {
+ return false;
+ }
+
+ check = crlX509.getNextUpdate();
+ if (check == null)
+ {
+ return false;
+ }
+ else if (!dateAndTime.before(check))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns a copy of this object.
+ *
+ * @return the copy
+ */
+ public Object clone()
+ {
+ try
+ {
+ X509CRLSelector copy = (X509CRLSelector)super.clone();
+ if (issuerNames != null)
+ {
+ copy.issuerNames = new HashSet();
+ Iterator iter = issuerNames.iterator();
+ Object obj;
+ while (iter.hasNext())
+ {
+ obj = iter.next();
+ if (obj instanceof byte[])
+ {
+ copy.issuerNames.add(((byte[])obj).clone());
+ }
+ else
+ {
+ copy.issuerNames.add(obj);
+ }
+ }
+ copy.issuerNamesX509 = new HashSet(issuerNamesX509);
+ }
+ return copy;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ /* Cannot happen */
+ throw new InternalError(e.toString());
+ }
+ }
+
+ /**
+ * Decides whether a <code>CRL</code> should be selected.
+ *
+ * @param crl
+ * the <code>CRL</code> to be checked
+ *
+ * @return <code>true</code> if the <code>CRL</code> should be selected,
+ * <code>false</code> otherwise
+ */
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof X509CRLSelector))
+ {
+ return false;
+ }
+
+ X509CRLSelector equalsCRL = (X509CRLSelector)obj;
+
+ if (!equals(dateAndTime, equalsCRL.dateAndTime))
+ {
+ return false;
+ }
+
+ if (!equals(minCRL, equalsCRL.minCRL))
+ {
+ return false;
+ }
+
+ if (!equals(maxCRL, equalsCRL.maxCRL))
+ {
+ return false;
+ }
+
+ if (!equals(issuerNamesX509, equalsCRL.issuerNamesX509))
+ {
+ return false;
+ }
+
+ if (!equals(certChecking, equalsCRL.certChecking))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return <code>true</code> if two Objects are unequal.
+ * This means that one is <code>null</code> and the other is
+ * not or <code>obj1.equals(obj2)</code> returns
+ * <code>false</code>.
+ **/
+ private boolean equals(Object obj1, Object obj2)
+ {
+ if (obj1 == null)
+ {
+ if (obj2 != null)
+ {
+ return true;
+ }
+ }
+ else if (!obj1.equals(obj2))
+ {
+ return true;
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java
new file mode 100644
index 000000000..0f1f814dd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java
@@ -0,0 +1,2468 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.ExtendedKeyUsage;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.util.Integers;
+
+/**
+ * A <code>CertSelector</code> that selects
+ * <code>X509Certificates that match all
+ * specified criteria. This class is particularly useful when
+ * selecting certificates from a CertStore to build a PKIX-compliant
+ * certification path.<br />
+ * <br />
+ * When first constructed, an <code>X509CertSelector</code> has no criteria enabled
+ * and each of the get methods return a default value (<code>null</code>, or -1 for
+ * the {@link #getBasicConstraints} method). Therefore, the {@link #match} method would
+ * return true for any <code>X509Certificate</code>. Typically, several criteria
+ * are enabled (by calling {@link #setIssuer} or {@link #setKeyUsage}, for instance) and
+ * then the <code>X509CertSelector</code> is passed to {@link CertStore#getCertificates} or
+ * some similar method.<br />
+ * <br />
+ * Several criteria can be enabled (by calling {@link #setIssuer} and
+ * {@link #setSerialNumber}, for example) such that the match method usually
+ * uniquely matches a single <code>X509Certificate</code>. We say usually, since it
+ * is possible for two issuing CAs to have the same distinguished name
+ * and each issue a certificate with the same serial number. Other
+ * unique combinations include the issuer, subject,
+ * subjectKeyIdentifier and/or the subjectPublicKey criteria.<br />
+ * <br />
+ * Please refer to RFC 2459 for definitions of the X.509 certificate
+ * extensions mentioned below.<br />
+ * <br />
+ * <b>Concurrent Access</b><br />
+ * <br />
+ * Unless otherwise specified, the methods defined in this class are
+ * not thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.<br />
+ * <br />
+ * <b>TODO: implement name constraints</b>
+ * <b>TODO: implement match check for path to names</b><br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.OIDTokenizer OIDTokenizer},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name},
+ * {@link org.spongycastle.asn1.x509.X509Extensions X509Extensions},
+ * {@link org.spongycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage},
+ * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId},
+ * {@link org.spongycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo},
+ * {@link org.spongycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier}
+ */
+public class X509CertSelector implements CertSelector
+{
+ private static final Hashtable keyPurposeIdMap = new Hashtable();
+ static
+ {
+ keyPurposeIdMap.put(KeyPurposeId.id_kp_serverAuth.getId(),
+ KeyPurposeId.id_kp_serverAuth);
+ keyPurposeIdMap.put(KeyPurposeId.id_kp_clientAuth.getId(),
+ KeyPurposeId.id_kp_clientAuth);
+ keyPurposeIdMap.put(KeyPurposeId.id_kp_codeSigning.getId(),
+ KeyPurposeId.id_kp_codeSigning);
+ keyPurposeIdMap.put(KeyPurposeId.id_kp_emailProtection.getId(),
+ KeyPurposeId.id_kp_emailProtection);
+ keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecEndSystem.getId(),
+ KeyPurposeId.id_kp_ipsecEndSystem);
+ keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecTunnel.getId(),
+ KeyPurposeId.id_kp_ipsecTunnel);
+ keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecUser.getId(),
+ KeyPurposeId.id_kp_ipsecUser);
+ keyPurposeIdMap.put(KeyPurposeId.id_kp_timeStamping.getId(),
+ KeyPurposeId.id_kp_timeStamping);
+ }
+
+ private X509Certificate x509Cert = null;
+
+ private BigInteger serialNumber = null;
+
+ private Object issuerDN = null;
+
+ private X509Name issuerDNX509 = null;
+
+ private Object subjectDN = null;
+
+ private X509Name subjectDNX509 = null;
+
+ private byte[] subjectKeyID = null;
+
+ private byte[] authorityKeyID = null;
+
+ private Date certValid = null;
+
+ private Date privateKeyValid = null;
+
+ private ASN1ObjectIdentifier subjectKeyAlgID = null;
+
+ private PublicKey subjectPublicKey = null;
+
+ private byte[] subjectPublicKeyByte = null;
+
+ private boolean[] keyUsage = null;
+
+ private Set keyPurposeSet = null;
+
+ private boolean matchAllSubjectAltNames = true;
+
+ private Set subjectAltNames = null;
+
+ private Set subjectAltNamesByte = null;
+
+ private int minMaxPathLen = -1;
+
+ private Set policy = null;
+
+ private Set policyOID = null;
+
+ private Set pathToNames = null;
+
+ private Set pathToNamesByte = null;
+
+ /**
+ * Creates an <code>X509CertSelector</code>. Initially, no criteria are
+ * set so any <code>X509Certificate</code> will match.
+ */
+ public X509CertSelector()
+ {
+ }
+
+ /**
+ * Sets the certificateEquals criterion. The specified
+ * <code>X509Certificate</code> must be equal to the
+ * <code>X509Certificate</code> passed to the match method. If
+ * <code>null</code>, then this check is not applied.<br />
+ * <br />
+ * This method is particularly useful when it is necessary to match a single
+ * certificate. Although other criteria can be specified in conjunction with
+ * the certificateEquals criterion, it is usually not practical or
+ * necessary.
+ *
+ * @param cert
+ * the X509Certificate to match (or <code>null</code>)
+ *
+ * @see #getCertificate()
+ */
+ public void setCertificate(X509Certificate cert)
+ {
+ x509Cert = cert;
+ }
+
+ /**
+ * Sets the serialNumber criterion. The specified serial number must match
+ * the certificate serial number in the <code>X509Certificate</code>. If
+ * <code>null</code>, any certificate serial number will do.
+ *
+ * @param serial
+ * the certificate serial number to match (or <code>null</code>)
+ *
+ * @see #getSerialNumber()
+ */
+ public void setSerialNumber(BigInteger serial)
+ {
+ serialNumber = serial;
+ }
+
+ /**
+ * Sets the issuer criterion. The specified distinguished name must match
+ * the issuer distinguished name in the <code>X509Certificate</code>. If
+ * <code>null</code>, any issuer distinguished name will do.<br />
+ * <br />
+ * If <code>issuerDN</code> is not <code>null</code>, it should contain
+ * a distinguished name, in RFC 2253 format.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for parsing the
+ * issuerDN.
+ *
+ * @param issuerDN
+ * a distinguished name in RFC 2253 format (or <code>null</code>)
+ *
+ * @exception IOException
+ * if a parsing error occurs (incorrect form for DN)
+ */
+ public void setIssuer(String issuerDN) throws IOException
+ {
+ if (issuerDN == null)
+ {
+ this.issuerDN = null;
+ this.issuerDNX509 = null;
+ }
+ else
+ {
+ X509Name nameX509;
+ try
+ {
+ nameX509 = new X509Name(issuerDN);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new IOException(ex.getMessage());
+ }
+ this.issuerDNX509 = nameX509;
+ this.issuerDN = issuerDN;
+ }
+ }
+
+ /**
+ * Sets the issuer criterion. The specified distinguished name must match
+ * the issuer distinguished name in the <code>X509Certificate</code>. If
+ * null is specified, the issuer criterion is disabled and any issuer
+ * distinguished name will do.<br />
+ * <br />
+ * If <code>issuerDN</code> is not <code>null</code>, it should contain
+ * a single DER encoded distinguished name, as defined in X.501. The ASN.1
+ * notation for this structure is as follows.<br />
+ * <br />
+ *
+ * <pre>
+ * Name ::= CHOICE {
+ * RDNSequence }
+ *
+ * RDNSequence ::= SEQUENCE OF RDN
+ *
+ * RDN ::=
+ * SET SIZE (1 .. MAX) OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ * ....
+ * DirectoryString ::= CHOICE {
+ * teletexString TeletexString (SIZE (1..MAX)),
+ * printableString PrintableString (SIZE (1..MAX)),
+ * universalString UniversalString (SIZE (1..MAX)),
+ * utf8String UTF8String (SIZE (1.. MAX)),
+ * bmpString BMPString (SIZE (1..MAX)) }
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * Note that the byte array specified here is cloned to protect against
+ * subsequent modifications.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name}
+ *
+ * @param issuerDN -
+ * a byte array containing the distinguished name in ASN.1 DER
+ * encoded form (or <code>null</code>)
+ *
+ * @exception IOException
+ * if an encoding error occurs (incorrect form for DN)
+ */
+ public void setIssuer(byte[] issuerDN) throws IOException
+ {
+ if (issuerDN == null)
+ {
+ this.issuerDN = null;
+ this.issuerDNX509 = null;
+ }
+ else
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(issuerDN);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object obj = derInStream.readObject();
+ if (obj instanceof ASN1Sequence)
+ {
+ this.issuerDNX509 = new X509Name((ASN1Sequence)obj);
+ }
+ else
+ {
+ throw new IOException("parsing error");
+ }
+ this.issuerDN = (byte[])issuerDN.clone();
+ }
+ }
+
+ /**
+ * Sets the subject criterion. The specified distinguished name must match
+ * the subject distinguished name in the <code>X509Certificate</code>. If
+ * null, any subject distinguished name will do.<br />
+ * <br />
+ * If <code>subjectDN</code> is not <code>null</code>, it should
+ * contain a distinguished name, in RFC 2253 format.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for parsing the
+ * subjectDN.
+ *
+ * @param subjectDN
+ * a distinguished name in RFC 2253 format (or <code>null</code>)
+ *
+ * @exception IOException
+ * if a parsing error occurs (incorrect form for DN)
+ */
+ public void setSubject(String subjectDN) throws IOException
+ {
+ if (subjectDN == null)
+ {
+ this.subjectDN = null;
+ this.subjectDNX509 = null;
+ }
+ else
+ {
+ X509Name nameX509;
+ try
+ {
+ nameX509 = new X509Name(subjectDN);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new IOException(ex.getMessage());
+ }
+
+ this.subjectDNX509 = nameX509;
+ this.subjectDN = subjectDN;
+ }
+ }
+
+ /**
+ * Sets the subject criterion. The specified distinguished name must match
+ * the subject distinguished name in the <code>X509Certificate</code>. If
+ * null, any subject distinguished name will do.<br />
+ * <br />
+ * If <code>subjectDN</code> is not <code>null</code>, it should
+ * contain a single DER encoded distinguished name, as defined in X.501. For
+ * the ASN.1 notation for this structure, see
+ * {@link #setIssuer(byte []) setIssuer(byte [] issuerDN)}.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name}
+ *
+ * @param subjectDN
+ * a byte array containing the distinguished name in ASN.1 DER
+ * format (or <code>null</code>)
+ *
+ * @exception IOException
+ * if an encoding error occurs (incorrect form for DN)
+ */
+ public void setSubject(byte[] subjectDN) throws IOException
+ {
+ if (subjectDN == null)
+ {
+ this.subjectDN = null;
+ this.subjectDNX509 = null;
+ }
+ else
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(subjectDN);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object obj = derInStream.readObject();
+
+ if (obj instanceof ASN1Sequence)
+ {
+ this.subjectDNX509 = new X509Name((ASN1Sequence)obj);
+ }
+ else
+ {
+ throw new IOException("parsing error");
+ }
+ this.subjectDN = (byte[])subjectDN.clone();
+ }
+ }
+
+ /**
+ * Sets the subjectKeyIdentifier criterion. The <code>X509Certificate</code>
+ * must contain a SubjectKeyIdentifier extension for which the contents of
+ * the extension matches the specified criterion value. If the criterion
+ * value is null, no subjectKeyIdentifier check will be done.<br />
+ * <br />
+ * If <code>subjectKeyID</code> is not <code>null</code>, it should
+ * contain a single DER encoded value corresponding to the contents of the
+ * extension value (not including the object identifier, criticality
+ * setting, and encapsulating OCTET STRING) for a SubjectKeyIdentifier
+ * extension. The ASN.1 notation for this structure follows.<br />
+ * <br />
+ *
+ * <pre>
+ * SubjectKeyIdentifier ::= KeyIdentifier
+ *
+ * KeyIdentifier ::= OCTET STRING
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * Since the format of subject key identifiers is not mandated by any
+ * standard, subject key identifiers are not parsed by the
+ * <code>X509CertSelector</code>. Instead, the values are compared using
+ * a byte-by-byte comparison.<br />
+ * <br />
+ * Note that the byte array supplied here is cloned to protect against
+ * subsequent modifications.
+ *
+ * @param subjectKeyID -
+ * the subject key identifier (or <code>null</code>)
+ *
+ * @see #getSubjectKeyIdentifier()
+ */
+ public void setSubjectKeyIdentifier(byte[] subjectKeyID)
+ {
+ if (subjectKeyID == null)
+ {
+ this.subjectKeyID = null;
+ }
+ else
+ {
+ this.subjectKeyID = (byte[])subjectKeyID.clone();
+ }
+ }
+
+ /**
+ * Sets the authorityKeyIdentifier criterion. The
+ * <code>X509Certificate</code> must contain an AuthorityKeyIdentifier
+ * extension for which the contents of the extension value matches the
+ * specified criterion value. If the criterion value is <code>null</code>,
+ * no authorityKeyIdentifier check will be done.<br />
+ * <br />
+ * If <code>authorityKeyID</code> is not <code>null</code>, it should
+ * contain a single DER encoded value corresponding to the contents of the
+ * extension value (not including the object identifier, criticality
+ * setting, and encapsulating OCTET STRING) for an AuthorityKeyIdentifier
+ * extension. The ASN.1 notation for this structure follows.<br />
+ * <br />
+ *
+ * <pre>
+ * AuthorityKeyIdentifier ::= SEQUENCE {
+ * keyIdentifier [0] KeyIdentifier OPTIONAL,
+ * authorityCertIssuer [1] GeneralNames OPTIONAL,
+ * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
+ *
+ * KeyIdentifier ::= OCTET STRING
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * Authority key identifiers are not parsed by the
+ * <code>X509CertSelector</code>. Instead, the values are compared using
+ * a byte-by-byte comparison.<br />
+ * <br />
+ * When the <code>keyIdentifier</code> field of
+ * <code>AuthorityKeyIdentifier</code> is populated, the value is usually
+ * taken from the SubjectKeyIdentifier extension in the issuer's
+ * certificate. Note, however, that the result of
+ * X509Certificate.getExtensionValue(<SubjectKeyIdentifier Object
+ * Identifier>) on the issuer's certificate may NOT be used directly as the
+ * input to setAuthorityKeyIdentifier. This is because the
+ * SubjectKeyIdentifier contains only a KeyIdentifier OCTET STRING, and not
+ * a SEQUENCE of KeyIdentifier, GeneralNames, and CertificateSerialNumber.
+ * In order to use the extension value of the issuer certificate's
+ * SubjectKeyIdentifier extension, it will be necessary to extract the value
+ * of the embedded KeyIdentifier OCTET STRING, then DER encode this OCTET
+ * STRING inside a SEQUENCE. For more details on SubjectKeyIdentifier, see
+ * {@link #setSubjectKeyIdentifier(byte[]) setSubjectKeyIdentifier(byte[] subjectKeyID }).<br />
+ * <br />
+ * Note also that the byte array supplied here is cloned to protect against
+ * subsequent modifications.
+ *
+ * @param authorityKeyID
+ * the authority key identifier (or <code>null</code>)
+ *
+ * @see #getAuthorityKeyIdentifier()
+ */
+ public void setAuthorityKeyIdentifier(byte[] authorityKeyID)
+ {
+ if (authorityKeyID == null)
+ {
+ this.authorityKeyID = null;
+ }
+ else
+ {
+ this.authorityKeyID = (byte[])authorityKeyID.clone();
+ }
+ }
+
+ /**
+ * Sets the certificateValid criterion. The specified date must fall within
+ * the certificate validity period for the X509Certificate. If
+ * <code>null</code>, no certificateValid check will be done.<br />
+ * <br />
+ * Note that the Date supplied here is cloned to protect against subsequent
+ * modifications.
+ *
+ * @param certValid
+ * the Date to check (or <code>null</code>)
+ *
+ * @see #getCertificateValid()
+ */
+ public void setCertificateValid(Date certValid)
+ {
+ if (certValid == null)
+ {
+ this.certValid = null;
+ }
+ else
+ {
+ this.certValid = new Date(certValid.getTime());
+ }
+ }
+
+ /**
+ * Sets the privateKeyValid criterion. The specified date must fall within
+ * the private key validity period for the X509Certificate. If
+ * <code>null</code>, no privateKeyValid check will be done.<br />
+ * <br />
+ * Note that the Date supplied here is cloned to protect against subsequent
+ * modifications.
+ *
+ * @param privateKeyValid
+ * the Date to check (or <code>null</code>)
+ *
+ * @see #getPrivateKeyValid()
+ */
+ public void setPrivateKeyValid(Date privateKeyValid)
+ {
+ if (privateKeyValid == null)
+ {
+ this.privateKeyValid = null;
+ }
+ else
+ {
+ this.privateKeyValid = new Date(privateKeyValid.getTime());
+ }
+ }
+
+ /**
+ * Sets the subjectPublicKeyAlgID criterion. The X509Certificate must
+ * contain a subject public key with the specified algorithm. If
+ * <code>null</code>, no subjectPublicKeyAlgID check will be done.
+ *
+ * @param oid
+ * The object identifier (OID) of the algorithm to check for (or
+ * <code>null</code>). An OID is represented by a set of
+ * nonnegative integers separated by periods.
+ *
+ * @exception IOException
+ * if the OID is invalid, such as the first component being
+ * not 0, 1 or 2 or the second component being greater than
+ * 39.
+ *
+ * @see #getSubjectPublicKeyAlgID()
+ */
+ public void setSubjectPublicKeyAlgID(String oid) throws IOException
+ {
+ if (oid != null)
+ {
+ CertUtil.parseOID(oid);
+ subjectKeyAlgID = new ASN1ObjectIdentifier(oid);
+ }
+ else
+ {
+ subjectKeyAlgID = null;
+ }
+ }
+
+ /**
+ * Sets the subjectPublicKey criterion. The X509Certificate must contain the
+ * specified subject public key. If null, no subjectPublicKey check will be
+ * done.
+ *
+ * @param key
+ * the subject public key to check for (or null)
+ *
+ * @see #getSubjectPublicKey()
+ */
+ public void setSubjectPublicKey(PublicKey key)
+ {
+ if (key == null)
+ {
+ subjectPublicKey = null;
+ subjectPublicKeyByte = null;
+ }
+ else
+ {
+ subjectPublicKey = key;
+ subjectPublicKeyByte = key.getEncoded();
+ }
+ }
+
+ /**
+ * Sets the subjectPublicKey criterion. The <code>X509Certificate</code>
+ * must contain the specified subject public key. If <code>null</code>,
+ * no subjectPublicKey check will be done.<br />
+ * <br />
+ * Because this method allows the public key to be specified as a byte
+ * array, it may be used for unknown key types.<br />
+ * <br />
+ * If key is not <code>null</code>, it should contain a single DER
+ * encoded SubjectPublicKeyInfo structure, as defined in X.509. The ASN.1
+ * notation for this structure is as follows.<br />
+ * <br />
+ *
+ * <pre>
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ * -- contains a value of the type
+ * -- registered for use with the
+ * -- algorithm object identifier value
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * Note that the byte array supplied here is cloned to protect against
+ * subsequent modifications.
+ *
+ * @param key
+ * a byte array containing the subject public key in ASN.1 DER
+ * form (or <code>null</code>)
+ *
+ * @exception IOException
+ * if an encoding error occurs (incorrect form for subject
+ * public key)
+ *
+ * @see #getSubjectPublicKey()
+ */
+ public void setSubjectPublicKey(byte[] key) throws IOException
+ {
+ if (key == null)
+ {
+ subjectPublicKey = null;
+ subjectPublicKeyByte = null;
+ }
+ else
+ {
+ subjectPublicKey = null;
+ subjectPublicKeyByte = (byte[])key.clone();
+ // TODO
+ // try to generyte PublicKey Object from subjectPublicKeyByte
+ }
+ }
+
+ /**
+ * Sets the keyUsage criterion. The X509Certificate must allow the specified
+ * keyUsage values. If null, no keyUsage check will be done. Note that an
+ * X509Certificate that has no keyUsage extension implicitly allows all
+ * keyUsage values.<br />
+ * <br />
+ * Note that the boolean array supplied here is cloned to protect against
+ * subsequent modifications.
+ *
+ * @param keyUsage
+ * a boolean array in the same format as the boolean array
+ * returned by X509Certificate.getKeyUsage(). Or
+ * <code>null</code>.
+ *
+ * @see #getKeyUsage()
+ */
+ public void setKeyUsage(boolean[] keyUsage)
+ {
+ if (keyUsage == null)
+ {
+ this.keyUsage = null;
+ }
+ else
+ {
+ this.keyUsage = (boolean[])keyUsage.clone();
+ }
+ }
+
+ /**
+ * Sets the extendedKeyUsage criterion. The <code>X509Certificate</code>
+ * must allow the specified key purposes in its extended key usage
+ * extension. If <code>keyPurposeSet</code> is empty or <code>null</code>,
+ * no extendedKeyUsage check will be done. Note that an
+ * <code>X509Certificate</code> that has no extendedKeyUsage extension
+ * implicitly allows all key purposes.<br />
+ * <br />
+ * Note that the Set is cloned to protect against subsequent modifications.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId}
+ *
+ * @param keyPurposeSet
+ * a <code>Set</code> of key purpose OIDs in string format (or
+ * <code>null</code>). Each OID is represented by a set of
+ * nonnegative integers separated by periods.
+ *
+ * @exception IOException
+ * if the OID is invalid, such as the first component being
+ * not 0, 1 or 2 or the second component being greater than
+ * 39.
+ *
+ * @see #getExtendedKeyUsage()
+ */
+ public void setExtendedKeyUsage(Set keyPurposeSet) throws IOException
+ {
+ if (keyPurposeSet == null || keyPurposeSet.isEmpty())
+ {
+ this.keyPurposeSet = keyPurposeSet;
+ }
+ else
+ {
+ this.keyPurposeSet = new HashSet();
+ Iterator iter = keyPurposeSet.iterator();
+ Object obj;
+ KeyPurposeId purposeID;
+ while (iter.hasNext())
+ {
+ obj = iter.next();
+ if (obj instanceof String)
+ {
+ purposeID = (KeyPurposeId)keyPurposeIdMap.get((String)obj);
+ if (purposeID == null)
+ {
+ throw new IOException("unknown purposeID "
+ + (String)obj);
+ }
+ this.keyPurposeSet.add(purposeID);
+ }
+ }
+ }
+ }
+
+ /**
+ * Enables/disables matching all of the subjectAlternativeNames specified in
+ * the {@link #setSubjectAlternativeNames setSubjectAlternativeNames} or
+ * {@link #addSubjectAlternativeName addSubjectAlternativeName} methods. If
+ * enabled, the <code>X509Certificate</code> must contain all of the
+ * specified subject alternative names. If disabled, the X509Certificate
+ * must contain at least one of the specified subject alternative names.<br />
+ * <br />
+ * The matchAllNames flag is <code>true</code> by default.
+ *
+ * @param matchAllNames
+ * if <code>true</code>, the flag is enabled; if
+ * <code>false</code>, the flag is disabled.
+ *
+ * @see #getMatchAllSubjectAltNames()
+ */
+ public void setMatchAllSubjectAltNames(boolean matchAllNames)
+ {
+ matchAllSubjectAltNames = matchAllNames;
+ }
+
+ /**
+ * Sets the subjectAlternativeNames criterion. The
+ * <code>X509Certificate</code> must contain all or at least one of the
+ * specified subjectAlternativeNames, depending on the value of the
+ * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br />
+ * <br />
+ * This method allows the caller to specify, with a single method call, the
+ * complete set of subject alternative names for the subjectAlternativeNames
+ * criterion. The specified value replaces the previous value for the
+ * subjectAlternativeNames criterion.<br />
+ * <br />
+ * The <code>names</code> parameter (if not <code>null</code>) is a
+ * <code>Collection</code> with one entry for each name to be included in
+ * the subject alternative name criterion. Each entry is a <code>List</code>
+ * whose first entry is an <code>Integer</code> (the name type, 0-8) and
+ * whose second entry is a <code>String</code> or a byte array (the name,
+ * in string or ASN.1 DER encoded form, respectively). There can be multiple
+ * names of the same type. If <code>null</code> is supplied as the value
+ * for this argument, no subjectAlternativeNames check will be performed.<br />
+ * <br />
+ * Each subject alternative name in the <code>Collection</code> may be
+ * specified either as a <code>String</code> or as an ASN.1 encoded byte
+ * array. For more details about the formats used, see
+ * {@link #addSubjectAlternativeName(int, String) addSubjectAlternativeName(int type, String name)}
+ * and
+ * {@link #addSubjectAlternativeName(int, byte[]) addSubjectAlternativeName(int type, byte [] name}).<br />
+ * <br />
+ * Note that the <code>names</code> parameter can contain duplicate names
+ * (same name and name type), but they may be removed from the
+ * <code>Collection</code> of names returned by the
+ * {@link #getSubjectAlternativeNames} method.<br />
+ * <br />
+ * Note that a deep copy is performed on the Collection to protect against
+ * subsequent modifications.
+ *
+ * @param names -
+ * a Collection of names (or null)
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ *
+ * @see #getSubjectAlternativeNames()
+ */
+ public void setSubjectAlternativeNames(Collection names) throws IOException
+ {
+ try
+ {
+ if (names == null || names.isEmpty())
+ {
+ subjectAltNames = null;
+ subjectAltNamesByte = null;
+ }
+ else
+ {
+ subjectAltNames = new HashSet();
+ subjectAltNamesByte = new HashSet();
+ Iterator iter = names.iterator();
+ List item;
+ int type;
+ Object data;
+ while (iter.hasNext())
+ {
+ item = (List)iter.next();
+ type = ((Integer)item.get(0)).intValue();
+ data = item.get(1);
+ if (data instanceof String)
+ {
+ addSubjectAlternativeName(type, (String)data);
+ }
+ else if (data instanceof byte[])
+ {
+ addSubjectAlternativeName(type, (byte[])data);
+ }
+ else
+ {
+ throw new IOException(
+ "parsing error: unknown data type");
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new IOException("parsing exception:\n" + ex.toString());
+ }
+ }
+
+ /**
+ * Adds a name to the subjectAlternativeNames criterion. The
+ * <code>X509Certificate</code> must contain all or at least one of the
+ * specified subjectAlternativeNames, depending on the value of the
+ * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br />
+ * <br />
+ * This method allows the caller to add a name to the set of subject
+ * alternative names. The specified name is added to any previous value for
+ * the subjectAlternativeNames criterion. If the specified name is a
+ * duplicate, it may be ignored.<br />
+ * <br />
+ * The name is provided in string format. RFC 822, DNS, and URI names use
+ * the well-established string formats for those types (subject to the
+ * restrictions included in RFC 2459). IPv4 address names are supplied using
+ * dotted quad notation. OID address names are represented as a series of
+ * nonnegative integers separated by periods. And directory names
+ * (distinguished names) are supplied in RFC 2253 format. No standard string
+ * format is defined for otherNames, X.400 names, EDI party names, IPv6
+ * address names, or any other type of names. They should be specified using
+ * the
+ * {@link #addSubjectAlternativeName(int, byte[]) addSubjectAlternativeName(int type, byte [] name)}
+ * method.
+ *
+ * @param type
+ * the name type (0-8, as specified in RFC 2459, section 4.2.1.7)
+ * @param name -
+ * the name in string form (not null)
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ */
+ public void addSubjectAlternativeName(int type, String name)
+ throws IOException
+ {
+ // TODO full implementation of CertUtil.parseGeneralName
+ byte[] encoded = CertUtil.parseGeneralName(type, name);
+ List tmpList = new ArrayList();
+ tmpList.add(Integers.valueOf(type));
+ tmpList.add(name);
+ subjectAltNames.add(tmpList);
+ tmpList.set(1, encoded);
+ subjectAltNamesByte.add(tmpList);
+ }
+
+ /**
+ * Adds a name to the subjectAlternativeNames criterion. The
+ * <code>X509Certificate</code> must contain all or at least one of the
+ * specified subjectAlternativeNames, depending on the value of the
+ * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br />
+ * <br />
+ * This method allows the caller to add a name to the set of subject
+ * alternative names. The specified name is added to any previous value for
+ * the subjectAlternativeNames criterion. If the specified name is a
+ * duplicate, it may be ignored.<br />
+ * <br />
+ * The name is provided as a byte array. This byte array should contain the
+ * DER encoded name, as it would appear in the GeneralName structure defined
+ * in RFC 2459 and X.509. The encoded byte array should only contain the
+ * encoded value of the name, and should not include the tag associated with
+ * the name in the GeneralName structure. The ASN.1 definition of this
+ * structure appears below.<br />
+ * <br />
+ *
+ * <pre>
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * Note that the byte array supplied here is cloned to protect against
+ * subsequent modifications.<br />
+ * <br />
+ * <b>TODO: check encoded format</b>
+ *
+ * @param type
+ * the name type (0-8, as listed above)
+ * @param name
+ * a byte array containing the name in ASN.1 DER encoded form
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ */
+ public void addSubjectAlternativeName(int type, byte[] name)
+ throws IOException
+ {
+ // TODO check encoded format
+ List tmpList = new ArrayList();
+ tmpList.add(Integers.valueOf(type));
+ tmpList.add(name.clone());
+ subjectAltNames.add(tmpList);
+ subjectAltNamesByte.add(tmpList);
+ }
+
+ /**
+ * Sets the name constraints criterion. The <code>X509Certificate</code>
+ * must have subject and subject alternative names that meet the specified
+ * name constraints.<br />
+ * <br />
+ * The name constraints are specified as a byte array. This byte array
+ * should contain the DER encoded form of the name constraints, as they
+ * would appear in the NameConstraints structure defined in RFC 2459 and
+ * X.509. The ASN.1 definition of this structure appears below.<br />
+ * <br />
+ *
+ * <pre>
+ * NameConstraints ::= SEQUENCE {
+ * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ *
+ * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ *
+ * GeneralSubtree ::= SEQUENCE {
+ * base GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL }
+ *
+ * BaseDistance ::= INTEGER (0..MAX)
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * Note that the byte array supplied here is cloned to protect against
+ * subsequent modifications.<br />
+ * <br />
+ * <b>TODO: implement this</b>
+ *
+ * @param bytes
+ * a byte array containing the ASN.1 DER encoding of a
+ * NameConstraints extension to be used for checking name
+ * constraints. Only the value of the extension is included, not
+ * the OID or criticality flag. Can be <code>null</code>, in
+ * which case no name constraints check will be performed
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ * @exception UnsupportedOperationException
+ * because this method is not supported
+ * @see #getNameConstraints()
+ */
+ public void setNameConstraints(byte[] bytes) throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Sets the basic constraints constraint. If the value is greater than or
+ * equal to zero, <code>X509Certificates</code> must include a
+ * basicConstraints extension with a pathLen of at least this value. If the
+ * value is -2, only end-entity certificates are accepted. If the value is
+ * -1, no check is done.<br />
+ * <br />
+ * This constraint is useful when building a certification path forward
+ * (from the target toward the trust anchor. If a partial path has been
+ * built, any candidate certificate must have a maxPathLen value greater
+ * than or equal to the number of certificates in the partial path.
+ *
+ * @param minMaxPathLen
+ * the value for the basic constraints constraint
+ *
+ * @exception IllegalArgumentException
+ * if the value is less than -2
+ *
+ * @see #getBasicConstraints()
+ */
+ public void setBasicConstraints(int minMaxPathLen)
+ {
+ if (minMaxPathLen < -2)
+ {
+ throw new IllegalArgumentException("minMaxPathLen must be >= -2");
+ }
+
+ this.minMaxPathLen = minMaxPathLen;
+ }
+
+ /**
+ * Sets the policy constraint. The X509Certificate must include at least one
+ * of the specified policies in its certificate policies extension. If
+ * certPolicySet is empty, then the X509Certificate must include at least
+ * some specified policy in its certificate policies extension. If
+ * certPolicySet is null, no policy check will be performed.<br />
+ * <br />
+ * Note that the Set is cloned to protect against subsequent modifications.<br />
+ * <br />
+ * <b>TODO: implement match check for this</b>
+ *
+ * @param certPolicySet
+ * a Set of certificate policy OIDs in string format (or null).
+ * Each OID is represented by a set of nonnegative integers
+ * separated by periods.
+ *
+ * @exception IOException
+ * if a parsing error occurs on the OID such as the first
+ * component is not 0, 1 or 2 or the second component is
+ * greater than 39.
+ *
+ * @see #getPolicy()
+ */
+ public void setPolicy(Set certPolicySet) throws IOException
+ {
+ if (certPolicySet == null)
+ {
+ policy = null;
+ policyOID = null;
+ }
+ else
+ {
+ policyOID = new HashSet();
+ Iterator iter = certPolicySet.iterator();
+ Object item;
+ while (iter.hasNext())
+ {
+ item = iter.next();
+ if (item instanceof String)
+ {
+ CertUtil.parseOID((String)item);
+ policyOID.add(new ASN1ObjectIdentifier((String)item));
+ }
+ else
+ {
+ throw new IOException(
+ "certPolicySet contains null values or non String objects");
+ }
+ }
+ policy = new HashSet(certPolicySet);
+ }
+ }
+
+ /**
+ * Sets the pathToNames criterion. The <code>X509Certificate</code> must
+ * not include name constraints that would prohibit building a path to the
+ * specified names.<br />
+ * <br />
+ * This method allows the caller to specify, with a single method call, the
+ * complete set of names which the <code>X509Certificates</code>'s name
+ * constraints must permit. The specified value replaces the previous value
+ * for the pathToNames criterion.<br />
+ * <br />
+ * This constraint is useful when building a certification path forward
+ * (from the target toward the trust anchor. If a partial path has been
+ * built, any candidate certificate must not include name constraints that
+ * would prohibit building a path to any of the names in the partial path.<br />
+ * <br />
+ * The names parameter (if not <code>null</code>) is a
+ * <code>Collection</code> with one entry for each name to be included in
+ * the pathToNames criterion. Each entry is a <code>List</code> whose
+ * first entry is an Integer (the name type, 0-8) and whose second entry is
+ * a <code>String</code> or a byte array (the name, in string or ASN.1 DER
+ * encoded form, respectively). There can be multiple names of the same
+ * type. If <code>null</code> is supplied as the value for this argument,
+ * no pathToNames check will be performed.<br />
+ * <br />
+ * Each name in the Collection may be specified either as a String or as an
+ * ASN.1 encoded byte array. For more details about the formats used, see
+ * {@link #addPathToName(int, String) addPathToName(int type, String name)}
+ * and
+ * {@link #addPathToName(int, byte[]) addPathToName(int type, byte [] name)}.<br />
+ * <br />
+ * Note that the names parameter can contain duplicate names (same name and
+ * name type), but they may be removed from the Collection of names returned
+ * by the {@link #getPathToNames} method.<br />
+ * <br />
+ * Note that a deep copy is performed on the Collection to protect against
+ * subsequent modifications.<br />
+ * <br />
+ * <b>TODO: implement this match check for this</b>
+ *
+ * @param names
+ * a Collection with one entry per name (or <code>null</code>)
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ * @exception UnsupportedOperationException
+ * because this method is not supported
+ *
+ * @see #getPathToNames()
+ */
+ public void setPathToNames(Collection names) throws IOException
+ {
+ try
+ {
+ if (names == null || names.isEmpty())
+ {
+ pathToNames = null;
+ pathToNamesByte = null;
+ }
+ else
+ {
+ pathToNames = new HashSet();
+ pathToNamesByte = new HashSet();
+ Iterator iter = names.iterator();
+ List item;
+ int type;
+ Object data;
+
+ while (iter.hasNext())
+ {
+ item = (List)iter.next();
+ type = ((Integer)item.get(0)).intValue();
+ data = item.get(1);
+ if (data instanceof String)
+ {
+ addPathToName(type, (String)data);
+ }
+ else if (data instanceof byte[])
+ {
+ addPathToName(type, (byte[])data);
+ }
+ else
+ {
+ throw new IOException(
+ "parsing error: unknown data type");
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new IOException("parsing exception:\n" + ex.toString());
+ }
+ }
+
+ /**
+ * Adds a name to the pathToNames criterion. The
+ * <code>X509Certificate</code> must not include name constraints that
+ * would prohibit building a path to the specified name.<br />
+ * <br />
+ * This method allows the caller to add a name to the set of names which the
+ * <code>X509Certificates</code>'s name constraints must permit. The
+ * specified name is added to any previous value for the pathToNames
+ * criterion. If the name is a duplicate, it may be ignored.<br />
+ * <br />
+ * The name is provided in string format. RFC 822, DNS, and URI names use
+ * the well-established string formats for those types (subject to the
+ * restrictions included in RFC 2459). IPv4 address names are supplied using
+ * dotted quad notation. OID address names are represented as a series of
+ * nonnegative integers separated by periods. And directory names
+ * (distinguished names) are supplied in RFC 2253 format. No standard string
+ * format is defined for otherNames, X.400 names, EDI party names, IPv6
+ * address names, or any other type of names. They should be specified using
+ * the
+ * {@link #addPathToName(int, byte[]) addPathToName(int type, byte [] name)}
+ * method.<br />
+ * <br />
+ * <b>TODO: implement this match check for this</b>
+ *
+ * @param type
+ * the name type (0-8, as specified in RFC 2459, section 4.2.1.7)
+ * @param name
+ * the name in string form
+ *
+ * @exceptrion IOException if a parsing error occurs
+ */
+ public void addPathToName(int type, String name) throws IOException
+ {
+ // TODO full implementation of CertUtil.parseGeneralName
+ byte[] encoded = CertUtil.parseGeneralName(type, name);
+ List tmpList = new ArrayList();
+ tmpList.add(Integers.valueOf(type));
+ tmpList.add(name);
+ pathToNames.add(tmpList);
+ tmpList.set(1, encoded);
+ pathToNamesByte.add(tmpList);
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Adds a name to the pathToNames criterion. The
+ * <code>X509Certificate</code> must not include name constraints that
+ * would prohibit building a path to the specified name.<br />
+ * <br />
+ * This method allows the caller to add a name to the set of names which the
+ * <code>X509Certificates</code>'s name constraints must permit. The
+ * specified name is added to any previous value for the pathToNames
+ * criterion. If the name is a duplicate, it may be ignored.<br />
+ * <br />
+ * The name is provided as a byte array. This byte array should contain the
+ * DER encoded name, as it would appear in the GeneralName structure defined
+ * in RFC 2459 and X.509. The ASN.1 definition of this structure appears in
+ * the documentation for
+ * {@link #addSubjectAlternativeName(int,byte[]) addSubjectAlternativeName(int type, byte[] name)}.<br />
+ * <br />
+ * Note that the byte array supplied here is cloned to protect against
+ * subsequent modifications.<br />
+ * <br />
+ * <b>TODO: implement this match check for this</b>
+ *
+ * @param type
+ * the name type (0-8, as specified in RFC 2459, section 4.2.1.7)
+ * @param name
+ * a byte array containing the name in ASN.1 DER encoded form
+ *
+ * @exception IOException
+ * if a parsing error occurs
+ */
+ public void addPathToName(int type, byte[] name) throws IOException
+ {
+ // TODO check encoded format
+ List tmpList = new ArrayList();
+ tmpList.add(Integers.valueOf(type));
+ tmpList.add(name.clone());
+ pathToNames.add(tmpList);
+ pathToNamesByte.add(tmpList);
+ }
+
+ /**
+ * Returns the certificateEquals criterion. The specified
+ * <code>X509Certificate</code> must be equal to the
+ * <code>X509Certificate</code> passed to the match method. If
+ * <code>null</code>, this check is not applied.
+ *
+ * @retrun the <code>X509Certificate</code> to match (or <code>null</code>)
+ *
+ * @see #setCertificate(java.security.cert.X509Certificate)
+ */
+ public X509Certificate getCertificate()
+ {
+ return x509Cert;
+ }
+
+ /**
+ * Returns the serialNumber criterion. The specified serial number must
+ * match the certificate serial number in the <code>X509Certificate</code>.
+ * If <code>null</code>, any certificate serial number will do.
+ *
+ * @return the certificate serial number to match (or <code>null</code>)
+ *
+ * @see #setSerialNumber(java.math.BigInteger)
+ */
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ /**
+ * Returns the issuer criterion as a String. This distinguished name must
+ * match the issuer distinguished name in the <code>X509Certificate</code>.
+ * If <code>null</code>, the issuer criterion is disabled and any issuer
+ * distinguished name will do.<br />
+ * <br />
+ * If the value returned is not <code>null</code>, it is a distinguished
+ * name, in RFC 2253 format.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for formatiing
+ * byte[] issuerDN to String.
+ *
+ * @return the required issuer distinguished name in RFC 2253 format (or
+ * <code>null</code>)
+ */
+ public String getIssuerAsString()
+ {
+ if (issuerDN instanceof String)
+ {
+ return new String((String)issuerDN);
+ }
+ else if (issuerDNX509 != null)
+ {
+ return issuerDNX509.toString();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the issuer criterion as a byte array. This distinguished name
+ * must match the issuer distinguished name in the
+ * <code>X509Certificate</code>. If <code>null</code>, the issuer
+ * criterion is disabled and any issuer distinguished name will do.<br />
+ * <br />
+ * If the value returned is not <code>null</code>, it is a byte array
+ * containing a single DER encoded distinguished name, as defined in X.501.
+ * The ASN.1 notation for this structure is supplied in the documentation
+ * for {@link #setIssuer(byte[]) setIssuer(byte [] issuerDN)}.<br />
+ * <br />
+ * Note that the byte array returned is cloned to protect against subsequent
+ * modifications.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name} to gnerate byte[]
+ * output for String issuerDN.
+ *
+ * @return a byte array containing the required issuer distinguished name in
+ * ASN.1 DER format (or <code>null</code>)
+ *
+ * @exception IOException
+ * if an encoding error occurs
+ */
+ public byte[] getIssuerAsBytes() throws IOException
+ {
+ if (issuerDN instanceof byte[])
+ {
+ return (byte[])((byte[])issuerDN).clone();
+ }
+ else if (issuerDNX509 != null)
+ {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DEROutputStream derOutStream = new DEROutputStream(outStream);
+
+ derOutStream.writeObject(issuerDNX509.toASN1Primitive());
+ derOutStream.close();
+
+ return outStream.toByteArray();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the subject criterion as a String. This distinguished name must
+ * match the subject distinguished name in the <code>X509Certificate</code>.
+ * If <code>null</code>, the subject criterion is disabled and any
+ * subject distinguished name will do.<br />
+ * <br />
+ * If the value returned is not <code>null</code>, it is a distinguished
+ * name, in RFC 2253 format.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.x509.X509Name X509Name} for formatiing
+ * byte[] subjectDN to String.
+ *
+ * @return the required subject distinguished name in RFC 2253 format (or
+ * <code>null</code>)
+ */
+ public String getSubjectAsString()
+ {
+ if (subjectDN instanceof String)
+ {
+ return new String((String)subjectDN);
+ }
+ else if (subjectDNX509 != null)
+ {
+ return subjectDNX509.toString();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the subject criterion as a byte array. This distinguished name
+ * must match the subject distinguished name in the
+ * <code>X509Certificate</code>. If <code>null</code>, the subject
+ * criterion is disabled and any subject distinguished name will do.<br />
+ * <br />
+ * If the value returned is not <code>null</code>, it is a byte array
+ * containing a single DER encoded distinguished name, as defined in X.501.
+ * The ASN.1 notation for this structure is supplied in the documentation
+ * for {@link #setSubject(byte [] subjectDN) setSubject(byte [] subjectDN)}.<br />
+ * <br />
+ * Note that the byte array returned is cloned to protect against subsequent
+ * modifications.<br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name} to gnerate byte[]
+ * output for String subjectDN.
+ *
+ * @return a byte array containing the required subject distinguished name
+ * in ASN.1 DER format (or <code>null</code>)
+ *
+ * @exception IOException
+ * if an encoding error occurs
+ */
+ public byte[] getSubjectAsBytes() throws IOException
+ {
+ if (subjectDN instanceof byte[])
+ {
+ return (byte[])((byte[])subjectDN).clone();
+ }
+ else if (subjectDNX509 != null)
+ {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ DEROutputStream derOutStream = new DEROutputStream(outStream);
+
+ derOutStream.writeObject(subjectDNX509.toASN1Primitive());
+ derOutStream.close();
+
+ return outStream.toByteArray();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the subjectKeyIdentifier criterion. The
+ * <code>X509Certificate</code> must contain a SubjectKeyIdentifier
+ * extension with the specified value. If <code>null</code>, no
+ * subjectKeyIdentifier check will be done.<br />
+ * <br />
+ * Note that the byte array returned is cloned to protect against subsequent
+ * modifications.
+ *
+ * @return the key identifier (or <code>null</code>)
+ *
+ * @see #setSubjectKeyIdentifier
+ */
+ public byte[] getSubjectKeyIdentifier()
+ {
+ if (subjectKeyID != null)
+ {
+ return (byte[])subjectKeyID.clone();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the authorityKeyIdentifier criterion. The
+ * <code>X509Certificate</code> must contain a AuthorityKeyIdentifier
+ * extension with the specified value. If <code>null</code>, no
+ * authorityKeyIdentifier check will be done.<br />
+ * <br />
+ * Note that the byte array returned is cloned to protect against subsequent
+ * modifications.
+ *
+ * @return the key identifier (or <code>null</code>)
+ *
+ * @see #setAuthorityKeyIdentifier
+ */
+ public byte[] getAuthorityKeyIdentifier()
+ {
+ if (authorityKeyID != null)
+ {
+ return (byte[])authorityKeyID.clone();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the certificateValid criterion. The specified date must fall
+ * within the certificate validity period for the
+ * <code>X509Certificate</code>. If <code>null</code>, no
+ * certificateValid check will be done.<br />
+ * <br />
+ * Note that the <code>Date</code> returned is cloned to protect against
+ * subsequent modifications.
+ *
+ * @return the <code>Date</code> to check (or <code>null</code>)
+ *
+ * @see #setCertificateValid
+ */
+ public Date getCertificateValid()
+ {
+ if (certValid != null)
+ {
+ return new Date(certValid.getTime());
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the privateKeyValid criterion. The specified date must fall
+ * within the private key validity period for the
+ * <code>X509Certificate</code>. If <code>null</code>, no
+ * privateKeyValid check will be done.<br />
+ * <br />
+ * Note that the <code>Date</code> returned is cloned to protect against
+ * subsequent modifications.
+ *
+ * @return the <code>Date</code> to check (or <code>null</code>)
+ *
+ * @see #setPrivateKeyValid
+ */
+ public Date getPrivateKeyValid()
+ {
+ if (privateKeyValid != null)
+ {
+ return new Date(privateKeyValid.getTime());
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the subjectPublicKeyAlgID criterion. The
+ * <code>X509Certificate</code> must contain a subject public key with the
+ * specified algorithm. If <code>null</code>, no subjectPublicKeyAlgID
+ * check will be done.
+ *
+ * @return the object identifier (OID) of the signature algorithm to check
+ * for (or <code>null</code>). An OID is represented by a set of
+ * nonnegative integers separated by periods.
+ *
+ * @see #setSubjectPublicKeyAlgID
+ */
+ public String getSubjectPublicKeyAlgID()
+ {
+ if (subjectKeyAlgID != null)
+ {
+ return subjectKeyAlgID.toString();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the subjectPublicKey criterion. The <code>X509Certificate</code>
+ * must contain the specified subject public key. If <code>null</code>,
+ * no subjectPublicKey check will be done.
+ *
+ * @return the subject public key to check for (or <code>null</code>)
+ *
+ * @see #setSubjectPublicKey
+ */
+ public PublicKey getSubjectPublicKey()
+ {
+ return subjectPublicKey;
+ }
+
+ /**
+ * Returns the keyUsage criterion. The <code>X509Certificate</code> must
+ * allow the specified keyUsage values. If null, no keyUsage check will be
+ * done.<br />
+ * <br />
+ * Note that the boolean array returned is cloned to protect against
+ * subsequent modifications.
+ *
+ * @return a boolean array in the same format as the boolean array returned
+ * by
+ * {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}.
+ * Or <code>null</code>.
+ *
+ * @see #setKeyUsage
+ */
+ public boolean[] getKeyUsage()
+ {
+ if (keyUsage != null)
+ {
+ return (boolean[])keyUsage.clone();
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the extendedKeyUsage criterion. The <code>X509Certificate</code>
+ * must allow the specified key purposes in its extended key usage
+ * extension. If the <code>keyPurposeSet</code> returned is empty or
+ * <code>null</code>, no extendedKeyUsage check will be done. Note that
+ * an <code>X509Certificate</code> that has no extendedKeyUsage extension
+ * implicitly allows all key purposes.
+ *
+ * @return an immutable <code>Set</code> of key purpose OIDs in string
+ * format (or <code>null</code>)
+ * @see #setExtendedKeyUsage
+ */
+ public Set getExtendedKeyUsage()
+ {
+ if (keyPurposeSet == null || keyPurposeSet.isEmpty())
+ {
+ return keyPurposeSet;
+ }
+
+ Set returnSet = new HashSet();
+ Iterator iter = keyPurposeSet.iterator();
+ while (iter.hasNext())
+ {
+ returnSet.add(iter.next().toString());
+ }
+
+ return Collections.unmodifiableSet(returnSet);
+ }
+
+ /**
+ * Indicates if the <code>X509Certificate</code> must contain all or at
+ * least one of the subjectAlternativeNames specified in the
+ * {@link #setSubjectAlternativeNames setSubjectAlternativeNames} or
+ * {@link #addSubjectAlternativeName addSubjectAlternativeName} methods. If
+ * <code>true</code>, the <code>X509Certificate</code> must contain all
+ * of the specified subject alternative names. If <code>false</code>, the
+ * <code>X509Certificate</code> must contain at least one of the specified
+ * subject alternative names.
+ *
+ * @return <code>true</code> if the flag is enabled; <code>false</code>
+ * if the flag is disabled. The flag is <code>true</code> by
+ * default.
+ *
+ * @see #setMatchAllSubjectAltNames
+ */
+ public boolean getMatchAllSubjectAltNames()
+ {
+ return matchAllSubjectAltNames;
+ }
+
+ /**
+ * Returns a copy of the subjectAlternativeNames criterion. The
+ * <code>X509Certificate</code> must contain all or at least one of the
+ * specified subjectAlternativeNames, depending on the value of the
+ * matchAllNames flag (see {@link #getMatchAllSubjectAltNames
+ * getMatchAllSubjectAltNames}). If the value returned is <code>null</code>,
+ * no subjectAlternativeNames check will be performed.<br />
+ * <br />
+ * If the value returned is not <code>null</code>, it is a
+ * <code>Collection</code> with one entry for each name to be included in
+ * the subject alternative name criterion. Each entry is a <code>List</code>
+ * whose first entry is an <code>Integer</code> (the name type, 0-8) and
+ * whose second entry is a <code>String</code> or a byte array (the name,
+ * in string or ASN.1 DER encoded form, respectively). There can be multiple
+ * names of the same type. Note that the <code>Collection</code> returned
+ * may contain duplicate names (same name and name type).<br />
+ * <br />
+ * Each subject alternative name in the <code>Collection</code> may be
+ * specified either as a <code>String</code> or as an ASN.1 encoded byte
+ * array. For more details about the formats used, see
+ * {@link #addSubjectAlternativeName(int type, String name)
+ * addSubjectAlternativeName(int type, String name)} and
+ * {@link #addSubjectAlternativeName(int type, byte [] name)
+ * addSubjectAlternativeName(int type, byte [] name)}.<br />
+ * <br />
+ * Note that a deep copy is performed on the <code>Collection</code> to
+ * protect against subsequent modifications.
+ *
+ * @return a <code>Collection</code> of names (or <code>null</code>)
+ *
+ * @see #setSubjectAlternativeNames
+ */
+ public Collection getSubjectAlternativeNames()
+ {
+ if (subjectAltNames != null)
+ {
+ return null;
+ }
+
+ Set returnAltNames = new HashSet();
+ List returnList;
+ Iterator iter = subjectAltNames.iterator();
+ List obj;
+ while (iter.hasNext())
+ {
+ obj = (List)iter.next();
+ returnList = new ArrayList();
+ returnList.add(obj.get(0));
+ if (obj.get(1) instanceof byte[])
+ {
+ returnList.add(((byte[])obj.get(1)).clone());
+ }
+ else
+ {
+ returnList.add(obj.get(1));
+ }
+ returnAltNames.add(returnList);
+ }
+
+ return returnAltNames;
+ }
+
+ /**
+ * Returns the name constraints criterion. The <code>X509Certificate</code>
+ * must have subject and subject alternative names that meet the specified
+ * name constraints.<br />
+ * <br />
+ * The name constraints are returned as a byte array. This byte array
+ * contains the DER encoded form of the name constraints, as they would
+ * appear in the NameConstraints structure defined in RFC 2459 and X.509.
+ * The ASN.1 notation for this structure is supplied in the documentation
+ * for
+ * {@link #setNameConstraints(byte [] bytes) setNameConstraints(byte [] bytes)}.<br />
+ * <br />
+ * Note that the byte array returned is cloned to protect against subsequent
+ * modifications.<br />
+ * <br />
+ * <b>TODO: implement this</b>
+ *
+ * @return a byte array containing the ASN.1 DER encoding of a
+ * NameConstraints extension used for checking name constraints.
+ * <code>null</code> if no name constraints check will be
+ * performed.
+ *
+ * @exception UnsupportedOperationException
+ * because this method is not supported
+ *
+ * @see #setNameConstraints
+ */
+ public byte[] getNameConstraints()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the basic constraints constraint. If the value is greater than or
+ * equal to zero, the <code>X509Certificates</code> must include a
+ * basicConstraints extension with a pathLen of at least this value. If the
+ * value is -2, only end-entity certificates are accepted. If the value is
+ * -1, no basicConstraints check is done.
+ *
+ * @return the value for the basic constraints constraint
+ *
+ * @see #setBasicConstraints
+ */
+ public int getBasicConstraints()
+ {
+ return minMaxPathLen;
+ }
+
+ /**
+ * Returns the policy criterion. The <code>X509Certificate</code> must
+ * include at least one of the specified policies in its certificate
+ * policies extension. If the <code>Set</code> returned is empty, then the
+ * <code>X509Certificate</code> must include at least some specified
+ * policy in its certificate policies extension. If the <code>Set</code>
+ * returned is <code>null</code>, no policy check will be performed.
+ *
+ * @return an immutable <code>Set</code> of certificate policy OIDs in
+ * string format (or <code>null</code>)
+ *
+ * @see #setPolicy
+ */
+ public Set getPolicy()
+ {
+ if (policy == null)
+ {
+ return null;
+ }
+
+ return Collections.unmodifiableSet(policy);
+ }
+
+ /**
+ * Returns a copy of the pathToNames criterion. The
+ * <code>X509Certificate</code> must not include name constraints that
+ * would prohibit building a path to the specified names. If the value
+ * returned is <code>null</code>, no pathToNames check will be performed.<br />
+ * <br />
+ * If the value returned is not <code>null</code>, it is a
+ * <code>Collection</code> with one entry for each name to be included in
+ * the pathToNames criterion. Each entry is a <code>List</code> whose
+ * first entry is an <code>Integer</code> (the name type, 0-8) and whose
+ * second entry is a <code>String</code> or a byte array (the name, in
+ * string or ASN.1 DER encoded form, respectively). There can be multiple
+ * names of the same type. Note that the <code>Collection</code> returned
+ * may contain duplicate names (same name and name type).<br />
+ * <br />
+ * Each name in the <code>Collection</code> may be specified either as a
+ * <code>String</code> or as an ASN.1 encoded byte array. For more details
+ * about the formats used, see {@link #addPathToName(int type, String name)
+ * addPathToName(int type, String name)} and
+ * {@link #addPathToName(int type, byte [] name) addPathToName(int type,
+ * byte [] name)}.<br />
+ * <br />
+ * Note that a deep copy is performed on the <code>Collection</code> to
+ * protect against subsequent modifications.
+ *
+ * @return a <code>Collection</code> of names (or <code>null</code>)
+ *
+ * @see #setPathToNames
+ */
+ public Collection getPathToNames()
+ {
+ if (pathToNames == null)
+ {
+ return null;
+ }
+
+ Set returnPathToNames = new HashSet();
+ List returnList;
+ Iterator iter = pathToNames.iterator();
+ List obj;
+
+ while (iter.hasNext())
+ {
+ obj = (List)iter.next();
+ returnList = new ArrayList();
+ returnList.add(obj.get(0));
+ if (obj.get(1) instanceof byte[])
+ {
+ returnList.add(((byte[])obj.get(1)).clone());
+ }
+ else
+ {
+ returnList.add(obj.get(1));
+ }
+ returnPathToNames.add(returnList);
+ }
+
+ return returnPathToNames;
+ }
+
+ /**
+ * Return a printable representation of the <code>CertSelector</code>.<br />
+ * <br />
+ * <b>TODO: implement output for currently unsupported options(name
+ * constraints)</b><br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId}
+ *
+ * @return a <code>String</code> describing the contents of the
+ * <code>CertSelector</code>
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("X509CertSelector: [\n");
+ if (x509Cert != null)
+ {
+ sb.append(" Certificate: ").append(x509Cert).append('\n');
+ }
+ if (serialNumber != null)
+ {
+ sb.append(" Serial Number: ").append(serialNumber).append('\n');
+ }
+ if (issuerDN != null)
+ {
+ sb.append(" Issuer: ").append(getIssuerAsString()).append('\n');
+ }
+ if (subjectDN != null)
+ {
+ sb.append(" Subject: ").append(getSubjectAsString()).append('\n');
+ }
+ try
+ {
+ if (subjectKeyID != null)
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ subjectKeyID);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object derObject = derInStream.readObject();
+ sb.append(" Subject Key Identifier: ")
+ .append(ASN1Dump.dumpAsString(derObject)).append('\n');
+ }
+ if (authorityKeyID != null)
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ authorityKeyID);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object derObject = derInStream.readObject();
+ sb.append(" Authority Key Identifier: ")
+ .append(ASN1Dump.dumpAsString(derObject)).append('\n');
+ }
+ }
+ catch (IOException ex)
+ {
+ sb.append(ex.getMessage()).append('\n');
+ }
+ if (certValid != null)
+ {
+ sb.append(" Certificate Valid: ").append(certValid).append('\n');
+ }
+ if (privateKeyValid != null)
+ {
+ sb.append(" Private Key Valid: ").append(privateKeyValid)
+ .append('\n');
+ }
+ if (subjectKeyAlgID != null)
+ {
+ sb.append(" Subject Public Key AlgID: ")
+ .append(subjectKeyAlgID).append('\n');
+ }
+ if (subjectPublicKey != null)
+ {
+ sb.append(" Subject Public Key: ").append(subjectPublicKey)
+ .append('\n');
+ }
+ if (keyUsage != null)
+ {
+ sb.append(" Key Usage: ").append(keyUsage).append('\n');
+ }
+ if (keyPurposeSet != null)
+ {
+ sb.append(" Extended Key Usage: ").append(keyPurposeSet)
+ .append('\n');
+ }
+ if (policy != null)
+ {
+ sb.append(" Policy: ").append(policy).append('\n');
+ }
+ sb.append(" matchAllSubjectAltNames flag: ")
+ .append(matchAllSubjectAltNames).append('\n');
+ if (subjectAltNamesByte != null)
+ {
+ sb.append(" SubjectAlternativNames: \n[");
+ Iterator iter = subjectAltNamesByte.iterator();
+ List obj;
+ try
+ {
+ while (iter.hasNext())
+ {
+ obj = (List)iter.next();
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ (byte[])obj.get(1));
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object derObject = derInStream.readObject();
+ sb.append(" Type: ").append(obj.get(0)).append(" Data: ")
+ .append(ASN1Dump.dumpAsString(derObject)).append('\n');
+ }
+ }
+ catch (IOException ex)
+ {
+ sb.append(ex.getMessage()).append('\n');
+ }
+ sb.append("]\n");
+ }
+ if (pathToNamesByte != null)
+ {
+ sb.append(" PathToNamesNames: \n[");
+ Iterator iter = pathToNamesByte.iterator();
+ List obj;
+ try
+ {
+ while (iter.hasNext())
+ {
+ obj = (List)iter.next();
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ (byte[])obj.get(1));
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object derObject = derInStream.readObject();
+ sb.append(" Type: ").append(obj.get(0)).append(" Data: ")
+ .append(ASN1Dump.dumpAsString(derObject)).append('\n');
+ }
+ }
+ catch (IOException ex)
+ {
+ sb.append(ex.getMessage()).append('\n');
+ }
+ sb.append("]\n");
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ /**
+ * Decides whether a <code>Certificate</code> should be selected.<br />
+ * <br />
+ * <b>TODO: implement missing tests (name constraints and path to names)</b><br />
+ * <br />
+ * Uses {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.DERGeneralizedTime DERGeneralizedTime},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name},
+ * {@link org.spongycastle.asn1.x509.X509Extensions X509Extensions},
+ * {@link org.spongycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage},
+ * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId},
+ * {@link org.spongycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo},
+ * {@link org.spongycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier}
+ * to access X509 extensions
+ *
+ * @param cert
+ * the <code>Certificate</code> to be checked
+ *
+ * @return <code>true</code> if the <code>Certificate</code> should be
+ * selected, <code>false</code> otherwise
+ */
+ public boolean match(Certificate cert)
+ {
+ boolean[] booleanArray;
+ List tempList;
+ Iterator tempIter;
+
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+ X509Certificate certX509 = (X509Certificate)cert;
+
+ if (x509Cert != null && !x509Cert.equals(certX509))
+ {
+ return false;
+ }
+ if (serialNumber != null
+ && !serialNumber.equals(certX509.getSerialNumber()))
+ {
+ return false;
+ }
+ try
+ {
+ if (issuerDNX509 != null)
+ {
+ if (!issuerDNX509.equals(PrincipalUtil
+ .getIssuerX509Principal(certX509), true))
+ {
+ return false;
+ }
+ }
+ if (subjectDNX509 != null)
+ {
+ if (!subjectDNX509.equals(PrincipalUtil
+ .getSubjectX509Principal(certX509), true))
+ {
+ return false;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ return false;
+ }
+ if (subjectKeyID != null)
+ {
+ byte[] data = certX509
+ .getExtensionValue(X509Extensions.SubjectKeyIdentifier
+ .getId());
+ if (data == null)
+ {
+ return false;
+ }
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(data);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ byte[] testData = ((ASN1OctetString)derInputStream.readObject())
+ .getOctets();
+ if (!Arrays.equals(subjectKeyID, testData))
+ {
+ return false;
+ }
+ }
+ catch (IOException ex)
+ {
+ return false;
+ }
+ }
+ if (authorityKeyID != null)
+ {
+ byte[] data = certX509
+ .getExtensionValue(X509Extensions.AuthorityKeyIdentifier
+ .getId());
+ if (data == null)
+ {
+ return false;
+ }
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(data);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ byte[] testData = ((ASN1OctetString)derInputStream.readObject())
+ .getOctets();
+ if (!Arrays.equals(authorityKeyID, testData))
+ {
+ return false;
+ }
+ }
+ catch (IOException ex)
+ {
+ return false;
+ }
+ }
+ if (certValid != null)
+ {
+ if (certX509.getNotAfter() != null
+ && certValid.after(certX509.getNotAfter()))
+ {
+ return false;
+ }
+ if (certX509.getNotBefore() != null
+ && certValid.before(certX509.getNotBefore()))
+ {
+ return false;
+ }
+ }
+ if (privateKeyValid != null)
+ {
+ try
+ {
+ byte[] data = certX509
+ .getExtensionValue(X509Extensions.PrivateKeyUsagePeriod
+ .getId());
+ if (data != null)
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ data);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ inStream = new ByteArrayInputStream(
+ ((ASN1OctetString)derInputStream.readObject())
+ .getOctets());
+ derInputStream = new ASN1InputStream(inStream);
+ // TODO fix this, Sequence contains tagged objects
+ ASN1Sequence derObject = (ASN1Sequence)derInputStream
+ .readObject();
+ DERGeneralizedTime derDate = DERGeneralizedTime
+ .getInstance(derObject.getObjectAt(0));
+ SimpleDateFormat dateF = new SimpleDateFormat(
+ "yyyyMMddHHmmssZ");
+ if (privateKeyValid.before(dateF.parse(derDate.getTime())))
+ {
+ return false;
+ }
+ derDate = DERGeneralizedTime.getInstance(derObject
+ .getObjectAt(1));
+ if (privateKeyValid.after(dateF.parse(derDate.getTime())))
+ {
+ return false;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ return false;
+ }
+ }
+ if (subjectKeyAlgID != null)
+ {
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ certX509.getPublicKey().getEncoded());
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(
+ (ASN1Sequence)derInputStream.readObject());
+ AlgorithmIdentifier algInfo = publicKeyInfo.getAlgorithmId();
+ if (!algInfo.getObjectId().equals(subjectKeyAlgID))
+ {
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ return false;
+ }
+ }
+ if (subjectPublicKeyByte != null)
+ {
+ if (!Arrays.equals(subjectPublicKeyByte, certX509.getPublicKey()
+ .getEncoded()))
+ {
+ return false;
+ }
+ }
+ if (subjectPublicKey != null)
+ {
+ if (!subjectPublicKey.equals(certX509.getPublicKey()))
+ {
+ return false;
+ }
+ }
+ if (keyUsage != null)
+ {
+ booleanArray = certX509.getKeyUsage();
+ if (booleanArray != null)
+ {
+ for (int i = 0; i < keyUsage.length; i++)
+ {
+ if (keyUsage[i]
+ && (booleanArray.length <= i || !booleanArray[i]))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ if (keyPurposeSet != null && !keyPurposeSet.isEmpty())
+ {
+ try
+ {
+ byte[] data = certX509
+ .getExtensionValue(X509Extensions.ExtendedKeyUsage
+ .getId());
+ if (data != null)
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ data);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ ExtendedKeyUsage extendedKeyUsage = ExtendedKeyUsage.getInstance(
+ derInputStream.readObject());
+ tempIter = keyPurposeSet.iterator();
+ while (tempIter.hasNext())
+ {
+ if (!extendedKeyUsage
+ .hasKeyPurposeId((KeyPurposeId)tempIter.next()))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ return false;
+ }
+ }
+ if (minMaxPathLen != -1)
+ {
+ if (minMaxPathLen == -2 && certX509.getBasicConstraints() != -1)
+ {
+ return false;
+ }
+ if (minMaxPathLen >= 0
+ && certX509.getBasicConstraints() < minMaxPathLen)
+ {
+ return false;
+ }
+ }
+ if (policyOID != null)
+ {
+ try
+ {
+ byte[] data = certX509
+ .getExtensionValue(X509Extensions.CertificatePolicies
+ .getId());
+ if (data == null)
+ {
+ return false;
+ }
+ if (!policyOID.isEmpty())
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ data);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ inStream = new ByteArrayInputStream(
+ ((ASN1OctetString)derInputStream.readObject())
+ .getOctets());
+ derInputStream = new ASN1InputStream(inStream);
+ Enumeration policySequence = ((ASN1Sequence)derInputStream
+ .readObject()).getObjects();
+ ASN1Sequence policyObject;
+ boolean test = false;
+ while (policySequence.hasMoreElements() && !test)
+ {
+ policyObject = (ASN1Sequence)policySequence
+ .nextElement();
+ if (policyOID.contains(policyObject.getObjectAt(0)))
+ {
+ test = true;
+ }
+ }
+ if (!test)
+ {
+ return false;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ return false;
+ }
+ }
+ if (subjectAltNamesByte != null)
+ {
+ try
+ {
+ byte[] data = certX509
+ .getExtensionValue(X509Extensions.SubjectAlternativeName
+ .getId());
+ if (data == null)
+ {
+ return false;
+ }
+ ByteArrayInputStream inStream = new ByteArrayInputStream(data);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ inStream = new ByteArrayInputStream(
+ ((ASN1OctetString)derInputStream.readObject())
+ .getOctets());
+ derInputStream = new ASN1InputStream(inStream);
+ Enumeration altNamesSequence = ((ASN1Sequence)derInputStream
+ .readObject()).getObjects();
+ ASN1TaggedObject altNameObject;
+ boolean test = false;
+ Set testSet = new HashSet(subjectAltNamesByte);
+ List testList;
+ ASN1Object derData;
+ ByteArrayOutputStream outStream;
+ DEROutputStream derOutStream;
+ while (altNamesSequence.hasMoreElements() && !test)
+ {
+ altNameObject = (ASN1TaggedObject)altNamesSequence
+ .nextElement();
+ testList = new ArrayList(2);
+ testList.add(Integers.valueOf(altNameObject.getTagNo()));
+ derData = altNameObject.getObject();
+ outStream = new ByteArrayOutputStream();
+ derOutStream = new DEROutputStream(outStream);
+ derOutStream.writeObject(derData);
+ derOutStream.close();
+ testList.add(outStream.toByteArray());
+
+ if (testSet.remove(testList))
+ {
+ test = true;
+ }
+
+ if (matchAllSubjectAltNames && !testSet.isEmpty())
+ {
+ test = false;
+ }
+ }
+ if (!test)
+ {
+ return false;
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns a copy of this object.
+ *
+ * @return the copy
+ */
+ public Object clone()
+ {
+ try
+ {
+ X509CertSelector copy = (X509CertSelector)super.clone();
+ if (issuerDN instanceof byte[])
+ {
+ copy.issuerDN = ((byte[])issuerDN).clone();
+ }
+ if (subjectDN instanceof byte[])
+ {
+ copy.subjectDN = ((byte[])subjectDN).clone();
+ }
+ if (subjectKeyID != null)
+ {
+ copy.subjectKeyID = (byte[])subjectKeyID.clone();
+ }
+ if (authorityKeyID != null)
+ {
+ copy.authorityKeyID = (byte[])authorityKeyID.clone();
+ }
+ if (subjectPublicKeyByte != null)
+ {
+ copy.subjectPublicKeyByte = (byte[])subjectPublicKeyByte
+ .clone();
+ }
+ if (keyUsage != null)
+ {
+ copy.keyUsage = (boolean[])keyUsage.clone();
+ }
+ if (keyPurposeSet != null)
+ {
+ copy.keyPurposeSet = new HashSet(keyPurposeSet);
+ }
+ if (policy != null)
+ {
+ copy.policy = new HashSet(policy);
+ copy.policyOID = new HashSet();
+ Iterator iter = policyOID.iterator();
+ while (iter.hasNext())
+ {
+ copy.policyOID.add(new ASN1ObjectIdentifier(
+ ((ASN1ObjectIdentifier)iter.next()).getId()));
+ }
+ }
+ if (subjectAltNames != null)
+ {
+ copy.subjectAltNames = new HashSet(getSubjectAlternativeNames());
+ Iterator iter = subjectAltNamesByte.iterator();
+ List obj;
+ List cloneObj;
+ while (iter.hasNext())
+ {
+ obj = (List)iter.next();
+ cloneObj = new ArrayList();
+ cloneObj.add(obj.get(0));
+ cloneObj.add(((byte[])obj.get(1)).clone());
+ copy.subjectAltNamesByte.add(cloneObj);
+ }
+ }
+ if (pathToNames != null)
+ {
+ copy.pathToNames = new HashSet(getPathToNames());
+ Iterator iter = pathToNamesByte.iterator();
+ List obj;
+ List cloneObj;
+ while (iter.hasNext())
+ {
+ obj = (List)iter.next();
+ cloneObj = new ArrayList();
+ cloneObj.add(obj.get(0));
+ cloneObj.add(((byte[])obj.get(1)).clone());
+ copy.pathToNamesByte.add(cloneObj);
+ }
+ }
+ return copy;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ /* Cannot happen */
+ throw new InternalError(e.toString());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java
new file mode 100644
index 000000000..f2c7e1990
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java
@@ -0,0 +1,12 @@
+
+package org.spongycastle.jce.cert;
+
+import java.util.Set;
+
+public interface X509Extension
+{
+ public abstract Set getCriticalExtensionOIDs();
+ public abstract byte[] getExtensionValue(String oid);
+ public abstract Set getNonCriticalExtensionOIDs();
+ public abstract boolean hasUnsupportedCriticalExtension();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html
new file mode 100644
index 000000000..c5cd3f6ad
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Compatibility API for the JDK 1.4 CertPath API.
+</body>
+</html>
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java
new file mode 100644
index 000000000..b238580f7
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.jce.exception;
+
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathBuilderException;
+
+public class ExtCertPathBuilderException
+ extends CertPathBuilderException
+ implements ExtException
+{
+ private Throwable cause;
+
+ public ExtCertPathBuilderException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathBuilderException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java
new file mode 100644
index 000000000..ec2b667d2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java
@@ -0,0 +1,30 @@
+package org.spongycastle.jce.exception;
+
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+
+public class ExtCertPathValidatorException
+ extends CertPathValidatorException
+ implements ExtException
+{
+
+ private Throwable cause;
+
+ public ExtCertPathValidatorException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathValidatorException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause, certPath, index);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
new file mode 100644
index 000000000..5ee182475
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
@@ -0,0 +1,1417 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.cert.CRLException;
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import org.spongycastle.jce.cert.PKIXParameters;
+import org.spongycastle.jce.cert.PolicyQualifierInfo;
+import org.spongycastle.jce.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import org.spongycastle.jce.cert.X509CRLSelector;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+import org.spongycastle.x509.X509Store;
+
+public class CertPathValidatorUtilities
+{
+ protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+ protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+ protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+ protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+ protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+ protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+ protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+ protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+ protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+ protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+ protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+ protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+ protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ protected static final String ANY_POLICY = "2.5.29.32.0";
+
+ protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+ protected static final int CRL_SIGN = 6;
+
+ protected static final String[] crlReasons = new String[]{
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the default provider
+ * for signature verification.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors)
+ throws AnnotatedException
+ {
+ return findTrustAnchor(cert, trustAnchors, null);
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the specified
+ * provider for signature verification, or the default provider
+ * if null.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @param sigProvider the provider to use for signature verification
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors,
+ String sigProvider)
+ throws AnnotatedException
+ {
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+ X509Principal certIssuer = getEncodedIssuerPrincipal(cert);
+
+ try
+ {
+ certSelectX509.setSubject(certIssuer.getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
+ }
+
+ Iterator iter = trustAnchors.iterator();
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X509Principal caName = new X509Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ verifyX509Certificate(cert, trustPublicKey, sigProvider);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ trustPublicKey = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ protected static void addAdditionalStoresFromAltNames(
+ X509Certificate cert,
+ ExtendedPKIXParameters pkixParams)
+ throws CertificateParsingException
+ {
+ // if in the IssuerAltName extension an URI
+ // is given, add an additinal X.509 store
+/*
+ if (cert.getIssuerAlternativeNames() != null)
+ {
+ Iterator it = cert.getIssuerAlternativeNames().iterator();
+ while (it.hasNext())
+ {
+ // look for URI
+ List list = (List)it.next();
+ if (list.get(0).equals(new Integer(GeneralName.uniformResourceIdentifier)))
+ {
+ // found
+ String temp = (String)list.get(1);
+ CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams);
+ }
+ }
+ }
+*/
+ }
+
+ /**
+ * Returns the issuer of an attribute certificate or certificate.
+ *
+ * @param cert The attribute certificate or certificate.
+ * @return The issuer as <code>X509Principal</code>.
+ */
+ protected static X509Principal getEncodedIssuerPrincipal(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+try
+{
+ return PrincipalUtil.getIssuerX509Principal((X509Certificate)cert);
+}
+catch (Exception e)
+{
+throw new IllegalStateException(e.toString());
+}
+ }
+ else
+ {
+ return (X509Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0];
+ }
+ }
+
+ protected static Date getValidDate(PKIXParameters paramsPKIX)
+ {
+ Date validDate = paramsPKIX.getDate();
+
+ if (validDate == null)
+ {
+ validDate = new Date();
+ }
+
+ return validDate;
+ }
+
+ protected static X509Principal getSubjectPrincipal(X509Certificate cert)
+ {
+try
+{
+ return PrincipalUtil.getSubjectX509Principal(cert);
+}
+catch (Exception e)
+{
+throw new IllegalStateException(e.toString());
+}
+ }
+
+ protected static boolean isSelfIssued(X509Certificate cert)
+ {
+ return cert.getSubjectDN().equals(cert.getIssuerDN());
+ }
+
+
+ /**
+ * Extract the value of the given extension, if it exists.
+ *
+ * @param ext The extension object.
+ * @param oid The object identifier to obtain.
+ * @throws AnnotatedException if the extension cannot be read.
+ */
+ protected static ASN1Primitive getExtensionValue(
+ java.security.cert.X509Extension ext,
+ String oid)
+ throws AnnotatedException
+ {
+ byte[] bytes = ext.getExtensionValue(oid);
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ return getObject(oid, bytes);
+ }
+
+ private static ASN1Primitive getObject(
+ String oid,
+ byte[] ext)
+ throws AnnotatedException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(ext);
+ ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
+
+ aIn = new ASN1InputStream(octs.getOctets());
+ return aIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("exception processing extension " + oid, e);
+ }
+ }
+
+ protected static X509Principal getIssuerPrincipal(X509CRL crl)
+ {
+try
+{
+ return PrincipalUtil.getIssuerX509Principal(crl);
+}
+catch (Exception e)
+{
+ throw new IllegalStateException(e.toString());
+}
+ }
+
+ protected static AlgorithmIdentifier getAlgorithmIdentifier(
+ PublicKey key)
+ throws CertPathValidatorException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ return info.getAlgorithmId();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
+ }
+ }
+
+ // crl checking
+
+
+ //
+ // policy checking
+ //
+
+ protected static final Set getQualifierSet(ASN1Sequence qualifiers)
+ throws CertPathValidatorException
+ {
+ Set pq = new HashSet();
+
+ if (qualifiers == null)
+ {
+ return pq;
+ }
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ Enumeration e = qualifiers.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
+ }
+ catch (IOException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+ }
+
+ bOut.reset();
+ }
+
+ return pq;
+ }
+
+ protected static PKIXPolicyNode removePolicyNode(
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
+
+ if (validPolicyTree == null)
+ {
+ return null;
+ }
+
+ if (_parent == null)
+ {
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ return null;
+ }
+ else
+ {
+ _parent.removeChild(_node);
+ removePolicyNodeRecurse(policyNodes, _node);
+
+ return validPolicyTree;
+ }
+ }
+
+ private static void removePolicyNodeRecurse(
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ policyNodes[_node.getDepth()].remove(_node);
+
+ if (_node.hasChildren())
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
+ removePolicyNodeRecurse(policyNodes, _child);
+ }
+ }
+ }
+
+
+ protected static boolean processCertD1i(
+ int index,
+ List[] policyNodes,
+ DERObjectIdentifier pOid,
+ Set pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
+ Set expectedPolicies = node.getExpectedPolicies();
+
+ if (expectedPolicies.contains(pOid.getId()))
+ {
+ Set childExpectedPolicies = new HashSet();
+ childExpectedPolicies.add(pOid.getId());
+
+ PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ childExpectedPolicies,
+ node,
+ pq,
+ pOid.getId(),
+ false);
+ node.addChild(child);
+ policyNodes[index].add(child);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected static void processCertD1ii(
+ int index,
+ List[] policyNodes,
+ DERObjectIdentifier _poid,
+ Set _pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Set _childExpectedPolicies = new HashSet();
+ _childExpectedPolicies.add(_poid.getId());
+
+ PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ _childExpectedPolicies,
+ _node,
+ _pq,
+ _poid.getId(),
+ false);
+ _node.addChild(_child);
+ policyNodes[index].add(_child);
+ return;
+ }
+ }
+ }
+
+ protected static void prepareNextCertB1(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ Map m_idp,
+ X509Certificate cert
+ )
+ throws AnnotatedException, CertPathValidatorException
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Certificate policies cannot be decoded.", e);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new AnnotatedException("Policy information cannot be decoded.", ex);
+ }
+ if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be built.", ex);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(
+ new ArrayList(), i,
+ (Set)m_idp.get(id_p),
+ p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode prepareNextCertB2(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ PKIXPolicyNode validPolicyTree)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return validPolicyTree;
+ }
+
+ protected static boolean isAnyPolicy(
+ Set policySet)
+ {
+ return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
+ }
+
+ protected static void addAdditionalStoreFromLocation(String location,
+ ExtendedPKIXParameters pkixParams)
+ {
+ }
+
+ /**
+ * Return a Collection of all certificates or attribute certificates found
+ * in the X509Store's that are matching the certSelect criteriums.
+ *
+ * @param certSelect a {@link Selector} object that will be used to select
+ * the certificates
+ * @param certStores a List containing only {@link X509Store} objects. These
+ * are used to search for certificates.
+ * @return a Collection of all found {@link X509Certificate} or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} objects.
+ * May be empty but never <code>null</code>.
+ */
+ protected static Collection findCertificates(X509CertStoreSelector certSelect,
+ List certStores)
+ throws AnnotatedException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store certStore = (X509Store)obj;
+ try
+ {
+ certs.addAll(certStore.getMatches(certSelect));
+ }
+ catch (StoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+ else
+ {
+ CertStore certStore = (CertStore)obj;
+
+ try
+ {
+ certs.addAll(certStore.getCertificates(certSelect));
+ }
+ catch (CertStoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from certificate store.",
+ e);
+ }
+ }
+ }
+ return certs;
+ }
+
+ protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
+ List certStores)
+ throws AnnotatedException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store certStore = (X509Store)obj;
+ try
+ {
+ certs.addAll(certStore.getMatches(certSelect));
+ }
+ catch (StoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+ }
+ return certs;
+ }
+
+ protected static void addAdditionalStoresFromCRLDistributionPoint(
+ CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Distribution points could not be read.", e);
+ }
+ for (int i = 0; i < dps.length; i++)
+ {
+ DistributionPointName dpn = dps[i].getDistributionPoint();
+ // look for URIs in fullName
+ if (dpn != null)
+ {
+ if (dpn.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] genNames = GeneralNames.getInstance(
+ dpn.getName()).getNames();
+ // look for an URI
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
+ {
+ String location = DERIA5String.getInstance(
+ genNames[j].getName()).getString();
+ CertPathValidatorUtilities
+ .addAdditionalStoreFromLocation(location,
+ pkixParams);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add the CRL issuers from the cRLIssuer field of the distribution point or
+ * from the certificate if not given to the issuer criterion of the
+ * <code>selector</code>.
+ * <p/>
+ * The <code>issuerPrincipals</code> are a collection with a single
+ * <code>X509Principal</code> for <code>X509Certificate</code>s. For
+ * {@link X509AttributeCertificate}s the issuer may contain more than one
+ * <code>X509Principal</code>.
+ *
+ * @param dp The distribution point.
+ * @param issuerPrincipals The issuers of the certificate or attribute
+ * certificate which contains the distribution point.
+ * @param selector The CRL selector.
+ * @param pkixParams The PKIX parameters containing the cert stores.
+ * @throws AnnotatedException if an exception occurs while processing.
+ * @throws ClassCastException if <code>issuerPrincipals</code> does not
+ * contain only <code>X509Principal</code>s.
+ */
+ protected static void getCRLIssuersFromDistributionPoint(
+ DistributionPoint dp,
+ Collection issuerPrincipals,
+ X509CRLSelector selector,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ List issuers = new ArrayList();
+ // indirect CRL
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ // look for a DN
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ issuers.add(new X509Principal(genNames[j].getName()
+ .toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.",
+ e);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * certificate issuer is CRL issuer, distributionPoint field MUST be
+ * present.
+ */
+ if (dp.getDistributionPoint() == null)
+ {
+ throw new AnnotatedException(
+ "CRL issuer is omitted from distribution point but no distributionPoint field present.");
+ }
+ // add and check issuer principals
+ for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); )
+ {
+ issuers.add((X509Principal)it.next());
+ }
+ }
+ // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
+ // distributionPoint
+// if (dp.getDistributionPoint() != null)
+// {
+// // look for nameRelativeToCRLIssuer
+// if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+// {
+// // append fragment to issuer, only one
+// // issuer can be there, if this is given
+// if (issuers.size() != 1)
+// {
+// throw new AnnotatedException(
+// "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+// }
+// ASN1Encodable relName = dp.getDistributionPoint().getName();
+// Iterator it = issuers.iterator();
+// List issuersTemp = new ArrayList(issuers.size());
+// while (it.hasNext())
+// {
+// Enumeration e = null;
+// try
+// {
+// e = ASN1Sequence.getInstance(
+// new ASN1InputStream(((X500Principal) it.next())
+// .getEncoded()).readObject()).getObjects();
+// }
+// catch (IOException ex)
+// {
+// throw new AnnotatedException(
+// "Cannot decode CRL issuer information.", ex);
+// }
+// ASN1EncodableVector v = new ASN1EncodableVector();
+// while (e.hasMoreElements())
+// {
+// v.add((ASN1Encodable) e.nextElement());
+// }
+// v.add(relName);
+// issuersTemp.add(new X500Principal(new DERSequence(v)
+// .getDEREncoded()));
+// }
+// issuers.clear();
+// issuers.addAll(issuersTemp);
+// }
+// }
+ Iterator it = issuers.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ selector.addIssuerName(((X509Principal)it.next()).getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException(
+ "Cannot decode CRL issuer information.", ex);
+ }
+ }
+ }
+
+ private static BigInteger getSerialNumber(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getSerialNumber();
+ }
+ else
+ {
+ return ((X509AttributeCertificate)cert).getSerialNumber();
+ }
+ }
+
+ protected static void getCertStatus(
+ Date validDate,
+ X509CRL crl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ X509CRLEntry crl_entry = null;
+
+ boolean isIndirect;
+ try
+ {
+ isIndirect = X509CRLObject.isIndirectCRL(crl);
+ }
+ catch (CRLException exception)
+ {
+ throw new AnnotatedException("Failed check for indirect CRL.", exception);
+ }
+
+ if (isIndirect)
+ {
+ if (!(crl instanceof X509CRLObject))
+ {
+ try
+ {
+ crl = new X509CRLObject(CertificateList.getInstance(crl.getEncoded()));
+ }
+ catch (CRLException exception)
+ {
+ throw new AnnotatedException("Failed to recode indirect CRL.", exception);
+ }
+ }
+
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+
+ X509Principal certIssuer = ((X509CRLEntryObject)crl_entry).getCertificateIssuer();
+
+ if (certIssuer == null)
+ {
+ certIssuer = getIssuerPrincipal(crl);
+ }
+
+ if (!getEncodedIssuerPrincipal(cert).equals(certIssuer))
+ {
+ return;
+ }
+ }
+ else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl)))
+ {
+ return; // not for our issuer, ignore
+ }
+ else
+ {
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+ }
+
+ DEREnumerated reasonCode = null;
+ if (crl_entry.hasExtensions())
+ {
+ try
+ {
+ reasonCode = DEREnumerated
+ .getInstance(CertPathValidatorUtilities
+ .getExtensionValue(crl_entry,
+ X509Extension.reasonCode.getId()));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Reason code CRL entry extension could not be decoded.",
+ e);
+ }
+ }
+
+ // for reason keyCompromise, caCompromise, aACompromise or
+ // unspecified
+ if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
+ || reasonCode == null
+ || reasonCode.getValue().intValue() == 0
+ || reasonCode.getValue().intValue() == 1
+ || reasonCode.getValue().intValue() == 2
+ || reasonCode.getValue().intValue() == 8)
+ {
+
+ // (i) or (j) (1)
+ if (reasonCode != null)
+ {
+ certStatus.setCertStatus(reasonCode.getValue().intValue());
+ }
+ // (i) or (j) (2)
+ else
+ {
+ certStatus.setCertStatus(CRLReason.unspecified);
+ }
+ certStatus.setRevocationDate(crl_entry.getRevocationDate());
+ }
+ }
+
+ /**
+ * Fetches delta CRLs according to RFC 3280 section 5.2.4.
+ *
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @param completeCRL The complete CRL the delta CRL is for.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the delta
+ * CRLs.
+ */
+ protected static Set getDeltaCRLs(Date currentDate,
+ ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
+ throws AnnotatedException
+ {
+
+ X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector();
+
+ // 5.2.4 (a)
+ try
+ {
+ deltaSelect.addIssuerName(CertPathValidatorUtilities
+ .getIssuerPrincipal(completeCRL).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL.", e);
+ }
+
+ BigInteger completeCRLNumber = null;
+ try
+ {
+ ASN1Primitive derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
+ CRL_NUMBER);
+ if (derObject != null)
+ {
+ completeCRLNumber = ASN1Integer.getInstance(derObject).getPositiveValue();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "CRL number extension could not be extracted from CRL.", e);
+ }
+
+ // 5.2.4 (b)
+ byte[] idp = null;
+ try
+ {
+ idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension value could not be read.",
+ e);
+ }
+
+ // 5.2.4 (d)
+
+ deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber
+ .add(BigInteger.valueOf(1)));
+
+ deltaSelect.setIssuingDistributionPoint(idp);
+ deltaSelect.setIssuingDistributionPointEnabled(true);
+
+ // 5.2.4 (c)
+ deltaSelect.setMaxBaseCRLNumber(completeCRLNumber);
+
+ // find delta CRLs
+ Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate);
+
+ Set result = new HashSet();
+
+ for (Iterator it = temp.iterator(); it.hasNext(); )
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (isDeltaCRL(crl))
+ {
+ result.add(crl);
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean isDeltaCRL(X509CRL crl)
+ {
+ Set critical = crl.getCriticalExtensionOIDs();
+
+ if (critical == null)
+ {
+ return false;
+ }
+
+ return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ }
+
+ /**
+ * Fetches complete CRLs according to RFC 3280.
+ *
+ * @param dp The distribution point for which the complete CRL
+ * @param cert The <code>X509Certificate</code> or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} for
+ * which the CRL should be searched.
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with complete
+ * CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the CRLs
+ * or no CRLs are found.
+ */
+ protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
+ Date currentDate, ExtendedPKIXParameters paramsPKIX)
+ throws AnnotatedException
+ {
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ try
+ {
+ Set issuers = new HashSet();
+ if (cert instanceof X509AttributeCertificate)
+ {
+ issuers.add(((X509AttributeCertificate)cert)
+ .getIssuer().getPrincipals()[0]);
+ }
+ else
+ {
+ issuers.add(getEncodedIssuerPrincipal(cert));
+ }
+ CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Could not get issuer information from distribution point.", e);
+ }
+ if (cert instanceof X509Certificate)
+ {
+ crlselect.setCertificateChecking((X509Certificate)cert);
+ }
+ else if (cert instanceof X509AttributeCertificate)
+ {
+ crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert);
+ }
+
+
+ crlselect.setCompleteCRLEnabled(true);
+
+ Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
+ if (crls.isEmpty())
+ {
+ if (cert instanceof X509AttributeCertificate)
+ {
+ X509AttributeCertificate aCert = (X509AttributeCertificate)cert;
+
+ throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\"");
+ }
+ else
+ {
+ X509Certificate xCert = (X509Certificate)cert;
+
+ throw new AnnotatedException("No CRLs found for issuer \"" + xCert.getIssuerDN() + "\"");
+ }
+ }
+ return crls;
+ }
+
+ protected static Date getValidCertDateFromValidityModel(
+ ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index)
+ throws AnnotatedException
+ {
+ if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ // if end cert use given signing/encryption/... time
+ if (index <= 0)
+ {
+ return CertPathValidatorUtilities.getValidDate(paramsPKIX);
+ // else use time when previous cert was created
+ }
+ else
+ {
+ if (index - 1 == 0)
+ {
+ DERGeneralizedTime dateOfCertgen = null;
+ try
+ {
+ byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId());
+ if (extBytes != null)
+ {
+ dateOfCertgen = DERGeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ if (dateOfCertgen != null)
+ {
+ try
+ {
+ return dateOfCertgen.getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new AnnotatedException(
+ "Date from date of cert gen extension could not be parsed.",
+ e);
+ }
+ }
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ else
+ {
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ }
+ }
+ else
+ {
+ return getValidDate(paramsPKIX);
+ }
+ }
+
+ /**
+ * Return the next working key inheriting DSA parameters if necessary.
+ * <p>
+ * This methods inherits DSA parameters from the indexed certificate or
+ * previous certificates in the certificate chain to the returned
+ * <code>PublicKey</code>. The list is searched upwards, meaning the end
+ * certificate is at position 0 and previous certificates are following.
+ * </p>
+ * <p>
+ * If the indexed certificate does not contain a DSA key this method simply
+ * returns the public key. If the DSA key already contains DSA parameters
+ * the key is also only returned.
+ * </p>
+ *
+ * @param certs The certification path.
+ * @param index The index of the certificate which contains the public key
+ * which should be extended with DSA parameters.
+ * @return The public key of the certificate in list position
+ * <code>index</code> extended with DSA parameters if applicable.
+ * @throws AnnotatedException if DSA parameters cannot be inherited.
+ */
+ protected static PublicKey getNextWorkingKey(List certs, int index)
+ throws CertPathValidatorException
+ {
+ Certificate cert = (Certificate)certs.get(index);
+ PublicKey pubKey = cert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ return pubKey;
+ }
+ DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey;
+ if (dsaPubKey.getParams() != null)
+ {
+ return dsaPubKey;
+ }
+ for (int i = index + 1; i < certs.size(); i++)
+ {
+ X509Certificate parentCert = (X509Certificate)certs.get(i);
+ pubKey = parentCert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ throw new CertPathValidatorException(
+ "DSA parameters cannot be inherited from previous certificate.");
+ }
+ DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey;
+ if (prevDSAPubKey.getParams() == null)
+ {
+ continue;
+ }
+ DSAParams dsaParams = prevDSAPubKey.getParams();
+ DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
+ dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+ try
+ {
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
+ return keyFactory.generatePublic(dsaPubKeySpec);
+ }
+ catch (Exception exception)
+ {
+ throw new RuntimeException(exception.getMessage());
+ }
+ }
+ throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ /**
+ * Find the issuer certificates of a given certificate.
+ *
+ * @param cert The certificate for which an issuer should be found.
+ * @param pkixParams
+ * @return A <code>Collection</code> object containing the issuer
+ * <code>X509Certificate</code>s. Never <code>null</code>.
+ * @throws AnnotatedException if an error occurs.
+ */
+ protected static Collection findIssuerCerts(
+ X509Certificate cert,
+ ExtendedPKIXBuilderParameters pkixParams)
+ throws AnnotatedException
+ {
+ X509CertStoreSelector certSelect = new X509CertStoreSelector();
+ Set certs = new HashSet();
+ try
+ {
+ certSelect.setSubject(PrincipalUtil.getSubjectX509Principal(cert).getEncoded());
+ }
+ catch (Exception ex)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+ }
+
+ Iterator iter;
+
+ try
+ {
+ List matches = new ArrayList();
+
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getCertStores()));
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getStores()));
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getAdditionalStores()));
+
+ iter = matches.iterator();
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate cannot be searched.", e);
+ }
+
+ X509Certificate issuer = null;
+ while (iter.hasNext())
+ {
+ issuer = (X509Certificate)iter.next();
+ // issuer cannot be verified because possible DSA inheritance
+ // parameters are missing
+ certs.add(issuer);
+ }
+ return certs;
+ }
+
+ protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
+ String sigProvider)
+ throws GeneralSecurityException
+ {
+ if (sigProvider == null)
+ {
+ cert.verify(publicKey);
+ }
+ else
+ {
+ cert.verify(publicKey, sigProvider);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java
new file mode 100644
index 000000000..a894cf84d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java
@@ -0,0 +1,104 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import org.spongycastle.jce.cert.CRLSelector;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.jce.cert.CertStoreException;
+import org.spongycastle.jce.cert.CertStoreParameters;
+import org.spongycastle.jce.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+public class CertStoreCollectionSpi extends CertStoreSpi
+{
+ private CollectionCertStoreParameters params;
+
+ public CertStoreCollectionSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof CollectionCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.CertStoreCollectionSpi: parameter must be a CollectionCertStoreParameters object\n" + params.toString());
+ }
+
+ this.params = (CollectionCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(
+ CertSelector selector)
+ throws CertStoreException
+ {
+ List col = new ArrayList();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof Certificate)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof Certificate) && selector.match((Certificate)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+
+
+ public Collection engineGetCRLs(
+ CRLSelector selector)
+ throws CertStoreException
+ {
+ List col = new ArrayList();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof CRL)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof CRL) && selector.match((CRL)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java
new file mode 100644
index 000000000..53c9d66e6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java
@@ -0,0 +1,146 @@
+package org.spongycastle.jce.provider;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.jcajce.provider.symmetric.util.PBE;
+
+public class JCEPBEKey
+ implements SecretKey
+{
+ String algorithm;
+ ASN1ObjectIdentifier oid;
+ int type;
+ int digest;
+ int keySize;
+ int ivSize;
+ CipherParameters param;
+ PBEKeySpec pbeKeySpec;
+ boolean tryWrong = false;
+
+ /**
+ * @param param
+ */
+ public JCEPBEKey(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ int type,
+ int digest,
+ int keySize,
+ int ivSize,
+ PBEKeySpec pbeKeySpec,
+ CipherParameters param)
+ {
+ this.algorithm = algorithm;
+ this.oid = oid;
+ this.type = type;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ this.pbeKeySpec = pbeKeySpec;
+ this.param = param;
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "RAW";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (param != null)
+ {
+ KeyParameter kParam;
+
+ if (param instanceof ParametersWithIV)
+ {
+ kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ kParam = (KeyParameter)param;
+ }
+
+ return kParam.getKey();
+ }
+ else
+ {
+ if (type == PBE.PKCS12)
+ {
+ return PBEParametersGenerator.PKCS12PasswordToBytes(pbeKeySpec.getPassword());
+ }
+ else
+ {
+ return PBEParametersGenerator.PKCS5PasswordToBytes(pbeKeySpec.getPassword());
+ }
+ }
+ }
+
+ int getType()
+ {
+ return type;
+ }
+
+ int getDigest()
+ {
+ return digest;
+ }
+
+ int getKeySize()
+ {
+ return keySize;
+ }
+
+ int getIvSize()
+ {
+ return ivSize;
+ }
+
+ CipherParameters getParam()
+ {
+ return param;
+ }
+
+ /**
+ * these should never be called.
+ */
+ int getIterationCount()
+ {
+ return 0;
+ }
+
+ byte[] getSalt()
+ {
+ return null;
+ }
+
+ /**
+ * Return the object identifier associated with this algorithm
+ *
+ * @return the oid for this PBE key
+ */
+ public ASN1ObjectIdentifier getOID()
+ {
+ return oid;
+ }
+
+ void setTryWrongPKCS12Zero(boolean tryWrong)
+ {
+ this.tryWrong = tryWrong;
+ }
+
+ boolean shouldTryWrongPKCS12()
+ {
+ return tryWrong;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java
new file mode 100644
index 000000000..b1c358b93
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java
@@ -0,0 +1,557 @@
+package org.spongycastle.jce.provider;
+
+import java.lang.reflect.Constructor;
+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.DESKeySpec;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.symmetric.util.PBE;
+
+public class JCESecretKeyFactory
+ extends SecretKeyFactorySpi
+ implements PBE
+{
+ protected String algName;
+ protected ASN1ObjectIdentifier algOid;
+
+ protected JCESecretKeyFactory(
+ String algName,
+ ASN1ObjectIdentifier algOid)
+ {
+ this.algName = algName;
+ this.algOid = algOid;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof SecretKeySpec)
+ {
+ return (SecretKey)keySpec;
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ try
+ {
+ Class[] parameters = { byte[].class };
+
+ Constructor c = keySpec.getConstructor(parameters);
+ Object[] p = new Object[1];
+
+ p[0] = key.getEncoded();
+
+ return (KeySpec)c.newInstance(p);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ protected SecretKey engineTranslateKey(
+ SecretKey key)
+ throws InvalidKeyException
+ {
+ if (key == null)
+ {
+ throw new InvalidKeyException("key parameter is null");
+ }
+
+ if (!key.getAlgorithm().equalsIgnoreCase(algName))
+ {
+ throw new InvalidKeyException("Key not of type " + algName + ".");
+ }
+
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ /*
+ * classes that inherit from us
+ */
+
+ static public class PBEKeyFactory
+ extends JCESecretKeyFactory
+ {
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public PBEKeyFactory(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ static public class DESPBEKeyFactory
+ extends JCESecretKeyFactory
+ {
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public DESPBEKeyFactory(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ static public class DES
+ extends JCESecretKeyFactory
+ {
+ public DES()
+ {
+ super("DES", null);
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESKeySpec)
+ {
+ DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DES");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ static public class DESede
+ extends JCESecretKeyFactory
+ {
+ public DESede()
+ {
+ super("DESede", null);
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+ else if (DESedeKeySpec.class.isAssignableFrom(keySpec))
+ {
+ byte[] bytes = key.getEncoded();
+
+ try
+ {
+ if (bytes.length == 16)
+ {
+ byte[] longKey = new byte[24];
+
+ System.arraycopy(bytes, 0, longKey, 0, 16);
+ System.arraycopy(bytes, 0, longKey, 16, 8);
+
+ return new DESedeKeySpec(longKey);
+ }
+ else
+ {
+ return new DESedeKeySpec(bytes);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESedeKeySpec)
+ {
+ DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DESede");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ /**
+ * PBEWithMD5AndDES
+ */
+ static public class PBEWithMD5AndDES
+ extends DESPBEKeyFactory
+ {
+ public PBEWithMD5AndDES()
+ {
+ super("PBEwithMD5andDES", null, true, PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithMD5AndRC2
+ */
+ static public class PBEWithMD5AndRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5AndRC2()
+ {
+ super("PBEwithMD5andRC2", null, true, PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndDES
+ */
+ static public class PBEWithSHA1AndDES
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA1AndDES()
+ {
+ super("PBEwithSHA1andDES", null, true, PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndRC2
+ */
+ static public class PBEWithSHA1AndRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA1AndRC2()
+ {
+ super("PBEwithSHA1andRC2", null, true, PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd3-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES3Key
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAndDES3Key()
+ {
+ super("PBEwithSHAandDES3Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, true, PKCS12, SHA1, 192, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd2-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES2Key
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAndDES2Key()
+ {
+ super("PBEwithSHAandDES2Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd128BitRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitRC2()
+ {
+ super("PBEwithSHAand128BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd40BitRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd40BitRC2()
+ {
+ super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbewithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAndTwofish-CBC
+ */
+ static public class PBEWithSHAAndTwofish
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAndTwofish()
+ {
+ super("PBEwithSHAandTwofish-CBC", null, true, PKCS12, SHA1, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC4
+ */
+ static public class PBEWithSHAAnd128BitRC4
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitRC4()
+ {
+ super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 128, 0);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC4
+ */
+ static public class PBEWithSHAAnd40BitRC4
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd40BitRC4()
+ {
+ super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 40, 0);
+ }
+ }
+
+ /**
+ * PBEWithHmacRIPEMD160
+ */
+ public static class PBEWithRIPEMD160
+ extends PBEKeyFactory
+ {
+ public PBEWithRIPEMD160()
+ {
+ super("PBEwithHmacRIPEMD160", null, false, PKCS12, RIPEMD160, 160, 0);
+ }
+ }
+
+ /**
+ * PBEWithHmacSHA
+ */
+ public static class PBEWithSHA
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA()
+ {
+ super("PBEwithHmacSHA", null, false, PKCS12, SHA1, 160, 0);
+ }
+ }
+
+ /**
+ * PBEWithHmacTiger
+ */
+ public static class PBEWithTiger
+ extends PBEKeyFactory
+ {
+ public PBEWithTiger()
+ {
+ super("PBEwithHmacTiger", null, false, PKCS12, TIGER, 192, 0);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And128BitAES-BC
+ */
+ static public class PBEWithSHAAnd128BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitAESBC()
+ {
+ super("PBEWithSHA1And128BitAES-CBC-BC", null, true, PKCS12, SHA1, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And192BitAES-BC
+ */
+ static public class PBEWithSHAAnd192BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd192BitAESBC()
+ {
+ super("PBEWithSHA1And192BitAES-CBC-BC", null, true, PKCS12, SHA1, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And256BitAES-BC
+ */
+ static public class PBEWithSHAAnd256BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd256BitAESBC()
+ {
+ super("PBEWithSHA1And256BitAES-CBC-BC", null, true, PKCS12, SHA1, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And128BitAES-BC
+ */
+ static public class PBEWithSHA256And128BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And128BitAESBC()
+ {
+ super("PBEWithSHA256And128BitAES-CBC-BC", null, true, PKCS12, SHA256, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And192BitAES-BC
+ */
+ static public class PBEWithSHA256And192BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And192BitAESBC()
+ {
+ super("PBEWithSHA256And192BitAES-CBC-BC", null, true, PKCS12, SHA256, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And256BitAES-BC
+ */
+ static public class PBEWithSHA256And256BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And256BitAESBC()
+ {
+ super("PBEWithSHA256And256BitAES-CBC-BC", null, true, PKCS12, SHA256, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And128BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And128BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And128BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And128BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And192BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And192BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And128BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And256BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And256BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java
new file mode 100644
index 000000000..cd56e0543
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java
@@ -0,0 +1,643 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.misc.CAST5CBCParameters;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.RC2CBCParameter;
+import org.spongycastle.jce.spec.IESParameterSpec;
+
+public abstract class JDKAlgorithmParameters
+ extends AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class IVAlgorithmParameters
+ extends JDKAlgorithmParameters
+ {
+ private byte[] iv;
+
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ return engineGetEncoded("ASN.1");
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
+ }
+
+ if (format.equals("RAW"))
+ {
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, iv.length);
+ return tmp;
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof IvParameterSpec))
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+ }
+
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ //
+ // check that we don't have a DER encoded octet string
+ //
+ if ((params.length % 8) != 0
+ && params[0] == 0x04 && params[1] == params.length - 2)
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+ ASN1OctetString oct = (ASN1OctetString)aIn.readObject();
+
+ params = oct.getOctets();
+ }
+
+ this.iv = new byte[params.length];
+
+ System.arraycopy(params, 0, iv, 0, iv.length);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+
+ try
+ {
+ ASN1OctetString oct = (ASN1OctetString)aIn.readObject();
+
+ engineInit(oct.getOctets());
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Exception decoding: " + e);
+ }
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "IV Parameters";
+ }
+ }
+
+ public static class RC2AlgorithmParameters
+ extends JDKAlgorithmParameters
+ {
+ private short[] table = {
+ 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+ 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+ 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+ 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+ 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+ 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+ 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+ 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+ 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+ 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+ 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+ 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+ 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+ 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+ 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+ 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
+ };
+
+ private short[] ekb = {
+ 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
+ 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
+ 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+ 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+ 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+ 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+ 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+ 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+ 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+ 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+ 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+ 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+ 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+ 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+ 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
+ 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
+ };
+
+ private byte[] iv;
+ private int parameterVersion = 58;
+
+ protected byte[] engineGetEncoded()
+ {
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, iv.length);
+ return tmp;
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ if (parameterVersion == -1)
+ {
+ return new RC2CBCParameter(engineGetEncoded()).getEncoded();
+ }
+ else
+ {
+ return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
+ }
+ }
+
+ if (format.equals("RAW"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == RC2ParameterSpec.class)
+ {
+ if (parameterVersion != -1)
+ {
+ if (parameterVersion < 256)
+ {
+ return new RC2ParameterSpec(ekb[parameterVersion], iv);
+ }
+ else
+ {
+ return new RC2ParameterSpec(parameterVersion, iv);
+ }
+ }
+ }
+
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec instanceof IvParameterSpec)
+ {
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+ else if (paramSpec instanceof RC2ParameterSpec)
+ {
+ int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+ if (effKeyBits != -1)
+ {
+ if (effKeyBits < 256)
+ {
+ parameterVersion = table[effKeyBits];
+ }
+ else
+ {
+ parameterVersion = effKeyBits;
+ }
+ }
+
+ this.iv = ((RC2ParameterSpec)paramSpec).getIV();
+ }
+ else
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.iv = new byte[params.length];
+
+ System.arraycopy(params, 0, iv, 0, iv.length);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+ RC2CBCParameter p = RC2CBCParameter.getInstance(aIn.readObject());
+
+ if (p.getRC2ParameterVersion() != null)
+ {
+ parameterVersion = p.getRC2ParameterVersion().intValue();
+ }
+
+ iv = p.getIV();
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "RC2 Parameters";
+ }
+ }
+
+ public static class CAST5AlgorithmParameters
+ extends JDKAlgorithmParameters
+ {
+ private byte[] iv;
+ private int keyLength = 128;
+
+ protected byte[] engineGetEncoded()
+ {
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, iv.length);
+ return tmp;
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return new CAST5CBCParameters(engineGetEncoded(), keyLength).getEncoded();
+ }
+
+ if (format.equals("RAW"))
+ {
+ return engineGetEncoded();
+ }
+
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to CAST5 parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec instanceof IvParameterSpec)
+ {
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+ else
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec required to initialise a CAST5 parameters algorithm parameters object");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.iv = new byte[params.length];
+
+ System.arraycopy(params, 0, iv, 0, iv.length);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+ CAST5CBCParameters p = CAST5CBCParameters.getInstance(aIn.readObject());
+
+ keyLength = p.getKeyLength();
+
+ iv = p.getIV();
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "CAST5 Parameters";
+ }
+ }
+
+ public static class PKCS12PBE
+ extends JDKAlgorithmParameters
+ {
+ PKCS12PBEParams params;
+
+ protected byte[] engineGetEncoded()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ try
+ {
+ dOut.writeObject(params);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Oooops! " + e.toString());
+ }
+
+ return bOut.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PBEParameterSpec.class)
+ {
+ return new PBEParameterSpec(params.getIV(),
+ params.getIterations().intValue());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PBEParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+ }
+
+ PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+ this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
+ pbeSpec.getIterationCount());
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+
+ this.params = PKCS12PBEParams.getInstance(aIn.readObject());
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "PKCS12 PBE Parameters";
+ }
+ }
+
+ public static class IES
+ extends JDKAlgorithmParameters
+ {
+ IESParameterSpec currentSpec;
+
+ /**
+ * in the abscence of a standard way of doing it this will do for
+ * now...
+ */
+ protected byte[] engineGetEncoded()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ try
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DEROctetString(currentSpec.getDerivationV()));
+ v.add(new DEROctetString(currentSpec.getEncodingV()));
+ v.add(new DERInteger(currentSpec.getMacKeySize()));
+
+ dOut.writeObject(new DERSequence(v));
+ dOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding IESParameters");
+ }
+
+ return bOut.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IESParameterSpec.class)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof IESParameterSpec))
+ {
+ throw new InvalidParameterSpecException("IESParameterSpec required to initialise a IES algorithm parameters object");
+ }
+
+ this.currentSpec = (IESParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+
+ try
+ {
+ ASN1Sequence s = (ASN1Sequence)aIn.readObject();
+
+ this.currentSpec = new IESParameterSpec(
+ ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+ ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+ ((DERInteger)s.getObjectAt(0)).getValue().intValue());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid IES Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid IES Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "IES Parameters";
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKPKCS12KeyStore.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKPKCS12KeyStore.java
new file mode 100644
index 000000000..1c8602377
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKPKCS12KeyStore.java
@@ -0,0 +1,1586 @@
+package org.spongycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+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.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BERConstructedOctetString;
+import org.spongycastle.asn1.BEROutputStream;
+import org.spongycastle.asn1.DERBMPString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.AuthenticatedSafe;
+import org.spongycastle.asn1.pkcs.CertBag;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.EncryptedData;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jce.interfaces.BCKeyStore;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.encoders.Hex;
+
+public class JDKPKCS12KeyStore
+ extends KeyStoreSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+ private static final int SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private Hashtable localIds = new Hashtable();
+ private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private Hashtable chainCerts = new Hashtable();
+ private Hashtable keyCerts = new Hashtable();
+
+ private static final String bcProvider = "SC";
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected SecureRandom random = new SecureRandom();
+
+ // use of final causes problems with JDK 1.2 compiler
+ private CertificateFactory certFact;
+ private ASN1ObjectIdentifier keyAlgorithm;
+ private ASN1ObjectIdentifier certAlgorithm;
+
+ private class CertId
+ {
+ byte[] id;
+
+ CertId(
+ PublicKey key)
+ {
+ this.id = createSubjectKeyId(key).getKeyIdentifier();
+ }
+
+ CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(id);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof CertId))
+ {
+ return false;
+ }
+
+ CertId cId = (CertId)o;
+
+ return Arrays.areEqual(id, cId.id);
+ }
+ }
+
+ public JDKPKCS12KeyStore(
+ String provider,
+ ASN1ObjectIdentifier keyAlgorithm,
+ ASN1ObjectIdentifier certAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+
+ try
+ {
+ if (provider != null)
+ {
+ certFact = CertificateFactory.getInstance("X.509", provider);
+ }
+ else
+ {
+ certFact = CertificateFactory.getInstance("X.509");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+ }
+ }
+
+ private SubjectKeyIdentifier createSubjectKeyId(
+ PublicKey pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence) ASN1Primitive.fromByteArray(pubKey.getEncoded()));
+
+ return new SubjectKeyIdentifier(info);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error creating key");
+ }
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (certs.get(alias) != null || keys.get(alias) != null);
+ }
+
+ /**
+ * this is not quite complete - we should follow up on the chain, a bit
+ * tricky if a certificate appears in more than one chain...
+ */
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Key k = (Key)keys.remove(alias);
+
+ Certificate c = (Certificate)certs.remove(alias);
+
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+
+ if (k != null)
+ {
+ String id = (String)localIds.remove(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.remove(id);
+ }
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+ }
+
+ if (c == null && k == null)
+ {
+ throw new KeyStoreException("no such entry as " + alias);
+ }
+ }
+
+ /**
+ * simply return the cert for the private key
+ */
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificate.");
+ }
+
+ Certificate c = (Certificate)certs.get(alias);
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ String id = (String)localIds.get(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.get(id);
+ }
+ else
+ {
+ c = (Certificate)keyCerts.get(alias);
+ }
+ }
+
+ return c;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration c = certs.elements();
+ Enumeration k = certs.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ c = keyCerts.elements();
+ k = keyCerts.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+ }
+
+ if (!engineIsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ Certificate c = engineGetCertificate(alias);
+
+ if (c != null)
+ {
+ Vector cs = new Vector();
+
+ while (c != null)
+ {
+ X509Certificate x509c = (X509Certificate)c;
+ Certificate nextC = null;
+
+ byte[] bytes = x509c.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(bytes);
+
+ byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+ aIn = new ASN1InputStream(authBytes);
+
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject());
+ if (id.getKeyIdentifier() != null)
+ {
+ nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+ }
+
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ Principal i = x509c.getIssuerDN();
+ Principal s = x509c.getSubjectDN();
+
+ if (!i.equals(s))
+ {
+ Enumeration e = chainCerts.keys();
+
+ while (e.hasMoreElements())
+ {
+ X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+ Principal sub = crt.getSubjectDN();
+ if (sub.equals(i))
+ {
+ try
+ {
+ x509c.verify(crt.getPublicKey());
+ nextC = crt;
+ break;
+ }
+ catch (Exception ex)
+ {
+ // continue
+ }
+ }
+ }
+ }
+ }
+
+ cs.addElement(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ Certificate[] certChain = new Certificate[cs.size()];
+
+ for (int i = 0; i != certChain.length; i++)
+ {
+ certChain[i] = (Certificate)cs.elementAt(i);
+ }
+
+ return certChain;
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ return new Date();
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getKey.");
+ }
+
+ return (Key)keys.get(alias);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ return (certs.get(alias) != null && keys.get(alias) == null);
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ return (keys.get(alias) != null);
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ if (keys.get(alias) != null)
+ {
+ throw new KeyStoreException("There is a key entry with the name " + alias + ".");
+ }
+
+ certs.put(alias, cert);
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ throw new RuntimeException("operation not supported");
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ if (keys.get(alias) != null)
+ {
+ engineDeleteEntry(alias);
+ }
+
+ keys.put(alias, key);
+ certs.put(alias, chain[0]);
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+ }
+ }
+
+ public int engineSize()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.size();
+ }
+
+ protected PrivateKey unwrapKey(
+ AlgorithmIdentifier algId,
+ byte[] data,
+ char[] password,
+ boolean wrongPKCS12Zero)
+ throws IOException
+ {
+ String algorithm = algId.getAlgorithm().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PrivateKey out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ SecretKey k = keyFact.generateSecret(pbeSpec);
+
+ ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ out = (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception unwrapping private key - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] wrapKey(
+ String algorithm,
+ Key key,
+ PKCS12PBEParams pbeParams,
+ char[] password)
+ throws IOException
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ byte[] out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+ out = cipher.wrap(key);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception encrypting data - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] cryptData(
+ boolean forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ boolean wrongPKCS12Zero,
+ byte[] data)
+ throws IOException
+ {
+ String algorithm = algId.getObjectId().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+ BCPBEKey key = (BCPBEKey) keyFact.generateSecret(pbeSpec);
+
+ key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+ int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+ cipher.init(mode, key, defParams);
+ return cipher.doFinal(data);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decrypting data - " + e.toString());
+ }
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+ bufIn.mark(10);
+
+ int head = bufIn.read();
+
+ if (head != 0x30)
+ {
+ throw new IOException("stream does not represent a PKCS12 key store");
+ }
+
+ bufIn.reset();
+
+ ASN1InputStream bIn = new ASN1InputStream(bufIn);
+ ASN1Sequence obj = (ASN1Sequence)bIn.readObject();
+ Pfx bag = Pfx.getInstance(obj);
+ ContentInfo info = bag.getAuthSafe();
+ Vector chain = new Vector();
+ boolean unmarkedKey = false;
+ boolean wrongPKCS12Zero = false;
+
+ if (bag.getMacData() != null) // check the mac code
+ {
+ MacData mData = bag.getMacData();
+ DigestInfo dInfo = mData.getMac();
+ AlgorithmIdentifier algId = dInfo.getAlgorithmId();
+ byte[] salt = mData.getSalt();
+ int itCount = mData.getIterationCount().intValue();
+
+ byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
+
+ try
+ {
+ byte[] res = calculatePbeMac(algId.getObjectId(), salt, itCount, password, false, data);
+ byte[] dig = dInfo.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ if (password.length > 0)
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ // Try with incorrect zero length password
+ res = calculatePbeMac(algId.getObjectId(), salt, itCount, password, true, data);
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ wrongPKCS12Zero = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+ }
+
+ keys = new IgnoresCaseHashtable();
+ localIds = new Hashtable();
+
+ if (info.getContentType().equals(data))
+ {
+ bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+ AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
+ ContentInfo[] c = authSafe.getContentInfo();
+
+ for (int i = 0; i != c.length; i++)
+ {
+ if (c[i].getContentType().equals(data))
+ {
+ ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+ if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ unmarkedKey = true;
+ keys.put("unmarked", privKey);
+ }
+ }
+ else if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else
+ {
+ System.out.println("extra in data " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else if (c[i].getContentType().equals(encryptedData))
+ {
+ EncryptedData d = EncryptedData.getInstance(c[i].getContent());
+ byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
+ password, wrongPKCS12Zero, d.getContent().getOctets());
+ ASN1Sequence seq = (ASN1Sequence) ASN1Primitive.fromByteArray(octets);
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+ if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet= (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else if (b.getBagId().equals(keyBag))
+ {
+ org.spongycastle.asn1.pkcs.PrivateKeyInfo kInfo = new org.spongycastle.asn1.pkcs.PrivateKeyInfo((ASN1Sequence)b.getBagValue());
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ System.out.println("extra in encryptedData " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else
+ {
+ System.out.println("extra " + c[i].getContentType().getId());
+ System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+ }
+ }
+ }
+
+ certs = new IgnoresCaseHashtable();
+ chainCerts = new Hashtable();
+ keyCerts = new Hashtable();
+
+ for (int i = 0; i != chain.size(); i++)
+ {
+ SafeBag b = (SafeBag)chain.elementAt(i);
+ CertBag cb = CertBag.getInstance(b.getBagValue());
+
+ if (!cb.getCertId().equals(x509Certificate))
+ {
+ throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
+ }
+
+ Certificate cert;
+
+ try
+ {
+ ByteArrayInputStream cIn = new ByteArrayInputStream(
+ ((ASN1OctetString)cb.getCertValue()).getOctets());
+ cert = certFact.generateCertificate(cIn);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+
+ //
+ // set the attributes
+ //
+ ASN1OctetString localId = null;
+ String alias = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Primitive attr = (ASN1Primitive)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
+ PKCS12BagAttributeCarrier bagAttr = null;
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(oid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(oid, attr);
+ }
+ }
+
+ if (oid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ }
+ else if (oid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+ if (unmarkedKey)
+ {
+ if (keyCerts.isEmpty())
+ {
+ String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+
+ keyCerts.put(name, cert);
+ keys.put(name, keys.remove("unmarked"));
+ }
+ }
+ else
+ {
+ //
+ // the local key id needs to override the friendly name
+ //
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ keyCerts.put(name, cert);
+ }
+ if (alias != null)
+ {
+ certs.put(alias, cert);
+ }
+ }
+ }
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ doStore(stream, password, false);
+ }
+
+ private void doStore(OutputStream stream, char[] password, boolean useDEREncoding)
+ throws IOException
+ {
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ //
+ // handle the key
+ //
+ ASN1EncodableVector keyS = new ASN1EncodableVector();
+
+
+ Enumeration ks = keys.keys();
+
+ while (ks.hasMoreElements())
+ {
+ byte[] kSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(kSalt);
+
+ String name = (String)ks.nextElement();
+ PrivateKey privKey = (PrivateKey)keys.get(name);
+ PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+ byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+ AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+ boolean attrSet = false;
+ ASN1EncodableVector kName = new ASN1EncodableVector();
+
+ if (privKey instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ Certificate ct = engineGetCertificate(name);
+
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+
+ kSeq.add(oid);
+ kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+ attrSet = true;
+
+ kName.add(new DERSequence(kSeq));
+ }
+ }
+
+ if (!attrSet)
+ {
+ //
+ // set a default friendly name (from the key id) and local id
+ //
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+ Certificate ct = engineGetCertificate(name);
+
+ kSeq.add(pkcs_9_at_localKeyId);
+ kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+ kName.add(new DERSequence(kSeq));
+
+ kSeq = new ASN1EncodableVector();
+
+ kSeq.add(pkcs_9_at_friendlyName);
+ kSeq.add(new DERSet(new DERBMPString(name)));
+
+ kName.add(new DERSequence(kSeq));
+ }
+
+ SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
+ keyS.add(kBag);
+ }
+
+ byte[] keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
+ BERConstructedOctetString keyString = new BERConstructedOctetString(keySEncoded);
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(cSalt);
+
+ ASN1EncodableVector certSeq = new ASN1EncodableVector();
+ PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+ Hashtable doneCerts = new Hashtable();
+
+ Enumeration cs = keys.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String name = (String)cs.nextElement();
+ Certificate cert = engineGetCertificate(name);
+ boolean cAttrSet = false;
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_localKeyId);
+ fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+ fName.add(new DERSequence(fSeq));
+
+ fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(name)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = certs.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String certId = (String)cs.nextElement();
+ Certificate cert = (Certificate)certs.get(certId);
+ boolean cAttrSet = false;
+
+ if (keys.get(certId) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(certId))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(certId)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = chainCerts.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ CertId certId = (CertId)cs.nextElement();
+ Certificate cert = (Certificate)chainCerts.get(certId);
+
+ if (doneCerts.get(cert) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+ }
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
+ byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
+ EncryptedData cInfo = new EncryptedData(data, cAlgId, new BERConstructedOctetString(certBytes));
+
+ ContentInfo[] info = new ContentInfo[]
+ {
+ new ContentInfo(data, keyString),
+ new ContentInfo(encryptedData, cInfo.toASN1Primitive())
+ };
+
+ AuthenticatedSafe auth = new AuthenticatedSafe(info);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream asn1Out;
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(bOut);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(bOut);
+ }
+
+ asn1Out.writeObject(auth);
+
+ byte[] pkg = bOut.toByteArray();
+
+ ContentInfo mainInfo = new ContentInfo(data, new BERConstructedOctetString(pkg));
+
+ //
+ // create the mac
+ //
+ byte[] mSalt = new byte[20];
+ int itCount = MIN_ITERATIONS;
+
+ random.nextBytes(mSalt);
+
+ byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+ MacData mData;
+
+ try
+ {
+ byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, new DERNull());
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mSalt, itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(stream);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(stream);
+ }
+
+ asn1Out.writeObject(pfx);
+ }
+
+ private static byte[] calculatePbeMac(
+ ASN1ObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ boolean wrongPkcs12Zero,
+ byte[] data)
+ throws Exception
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ BCPBEKey key = (BCPBEKey) keyFact.generateSecret(pbeSpec);
+ key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
+
+ Mac mac = Mac.getInstance(oid.getId(), bcProvider);
+ mac.init(key, defParams);
+ mac.update(data);
+ return mac.doFinal();
+ }
+
+ public static class BCPKCS12KeyStore
+ extends JDKPKCS12KeyStore
+ {
+ public BCPKCS12KeyStore()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class BCPKCS12KeyStore3DES
+ extends JDKPKCS12KeyStore
+ {
+ public BCPKCS12KeyStore3DES()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore
+ extends JDKPKCS12KeyStore
+ {
+ public DefPKCS12KeyStore()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore3DES
+ extends JDKPKCS12KeyStore
+ {
+ public DefPKCS12KeyStore3DES()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ private static class IgnoresCaseHashtable
+ {
+ private Hashtable orig = new Hashtable();
+ private Hashtable keys = new Hashtable();
+
+ public void put(String key, Object value)
+ {
+ String lower = Strings.toLowerCase(key);
+ String k = (String)keys.get(lower);
+ if (k != null)
+ {
+ orig.remove(k);
+ }
+
+ keys.put(lower, key);
+ orig.put(key, value);
+ }
+
+ public Enumeration keys()
+ {
+ return orig.keys();
+ }
+
+ public Object remove(String alias)
+ {
+ String k = (String)keys.remove(Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.remove(k);
+ }
+
+ public Object get(String alias)
+ {
+ String k = (String)keys.get(Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.get(k);
+ }
+
+ public Enumeration elements()
+ {
+ return orig.elements();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java
new file mode 100644
index 000000000..e3102c77d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java
@@ -0,0 +1,85 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.jce.MultiCertStoreParameters;
+
+import java.security.InvalidAlgorithmParameterException;
+import org.spongycastle.jce.cert.CRLSelector;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreException;
+import org.spongycastle.jce.cert.CertStoreParameters;
+import org.spongycastle.jce.cert.CertStoreSpi;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public class MultiCertStoreSpi
+ extends CertStoreSpi
+{
+ private MultiCertStoreParameters params;
+
+ public MultiCertStoreSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof MultiCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.MultiCertStoreSpi: parameter must be a MultiCertStoreParameters object\n" + params.toString());
+ }
+
+ this.params = (MultiCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(CertSelector certSelector)
+ throws CertStoreException
+ {
+ boolean searchAllStores = params.getSearchAllStores();
+ Iterator iter = params.getCertStores().iterator();
+ List allCerts = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST;
+
+ while (iter.hasNext())
+ {
+ CertStore store = (CertStore)iter.next();
+ Collection certs = store.getCertificates(certSelector);
+
+ if (searchAllStores)
+ {
+ allCerts.addAll(certs);
+ }
+ else if (!certs.isEmpty())
+ {
+ return certs;
+ }
+ }
+
+ return allCerts;
+ }
+
+ public Collection engineGetCRLs(CRLSelector crlSelector)
+ throws CertStoreException
+ {
+ boolean searchAllStores = params.getSearchAllStores();
+ Iterator iter = params.getCertStores().iterator();
+ List allCRLs = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST;
+
+ while (iter.hasNext())
+ {
+ CertStore store = (CertStore)iter.next();
+ Collection crls = store.getCRLs(crlSelector);
+
+ if (searchAllStores)
+ {
+ allCRLs.addAll(crls);
+ }
+ else if (!crls.isEmpty())
+ {
+ return crls;
+ }
+ }
+
+ return allCRLs;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java
new file mode 100644
index 000000000..3e22d9f6c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java
@@ -0,0 +1,155 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreException;
+import org.spongycastle.jce.cert.PKIXParameters;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509Store;
+
+public class PKIXCRLUtil
+{
+ public Set findCRLs(X509CRLStoreSelector crlselect, ExtendedPKIXParameters paramsPKIX, Date currentDate)
+ throws AnnotatedException
+ {
+ Set initialSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getAdditionalStores()));
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getStores()));
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+ }
+
+ Set finalSet = new HashSet();
+ Date validityDate = currentDate;
+
+ if (paramsPKIX.getDate() != null)
+ {
+ validityDate = paramsPKIX.getDate();
+ }
+
+ // based on RFC 5280 6.3.3
+ for (Iterator it = initialSet.iterator(); it.hasNext();)
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (crl.getNextUpdate().after(validityDate))
+ {
+ X509Certificate cert = crlselect.getCertificateChecking();
+
+ if (cert != null)
+ {
+ if (crl.getThisUpdate().before(cert.getNotAfter()))
+ {
+ finalSet.add(crl);
+ }
+ }
+ else
+ {
+ finalSet.add(crl);
+ }
+ }
+ }
+
+ return finalSet;
+ }
+
+ public Set findCRLs(X509CRLStoreSelector crlselect, PKIXParameters paramsPKIX)
+ throws AnnotatedException
+ {
+ Set completeSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ completeSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+ }
+
+ return completeSet;
+ }
+
+/**
+ * Return a Collection of all CRLs found in the X509Store's that are
+ * matching the crlSelect criteriums.
+ *
+ * @param crlSelect a {@link X509CRLStoreSelector} object that will be used
+ * to select the CRLs
+ * @param crlStores a List containing only
+ * {@link org.spongycastle.x509.X509Store X509Store} objects.
+ * These are used to search for CRLs
+ *
+ * @return a Collection of all found {@link java.security.cert.X509CRL X509CRL} objects. May be
+ * empty but never <code>null</code>.
+ */
+ private final Collection findCRLs(X509CRLStoreSelector crlSelect,
+ List crlStores) throws AnnotatedException
+ {
+ Set crls = new HashSet();
+ Iterator iter = crlStores.iterator();
+
+ AnnotatedException lastException = null;
+ boolean foundValidStore = false;
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store store = (X509Store)obj;
+
+ try
+ {
+ crls.addAll(store.getMatches(crlSelect));
+ foundValidStore = true;
+ }
+ catch (StoreException e)
+ {
+ lastException = new AnnotatedException(
+ "Exception searching in X.509 CRL store.", e);
+ }
+ }
+ else
+ {
+ CertStore store = (CertStore)obj;
+
+ try
+ {
+ crls.addAll(store.getCRLs(crlSelect));
+ foundValidStore = true;
+ }
+ catch (CertStoreException e)
+ {
+ lastException = new AnnotatedException(
+ "Exception searching in X.509 CRL store.", e);
+ }
+ }
+ }
+ if (!foundValidStore && lastException != null)
+ {
+ throw lastException;
+ }
+ return crls;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java
new file mode 100644
index 000000000..d02dd511f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java
@@ -0,0 +1,395 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathBuilderException;
+import org.spongycastle.jce.cert.CertPathBuilderResult;
+import org.spongycastle.jce.cert.CertPathBuilderSpi;
+import org.spongycastle.jce.cert.CertPathParameters;
+import org.spongycastle.jce.cert.CertPathValidator;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import org.spongycastle.jce.cert.CertificateFactory;
+import org.spongycastle.jce.cert.PKIXBuilderParameters;
+import org.spongycastle.jce.cert.PKIXBuilderParameters;
+import org.spongycastle.jce.cert.PKIXCertPathBuilderResult;
+import org.spongycastle.jce.cert.PKIXCertPathValidatorResult;
+import org.spongycastle.jce.cert.TrustAnchor;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.jce.PrincipalUtil;
+
+/**
+ * Implements the PKIX CertPathBuilding algorithem for BouncyCastle.
+ * <br />
+ * <b>MAYBE: implement more CertPath validation whil build path to omit invalid pathes</b>
+ *
+ * @see CertPathBuilderSpi
+ **/
+public class PKIXCertPathBuilderSpi
+ extends CertPathBuilderSpi
+{
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all
+ * information to build the CertPath
+ **/
+ public CertPathBuilderResult engineBuild(
+ CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXBuilderParameters)
+ && !(params instanceof ExtendedPKIXBuilderParameters))
+ {
+ throw new InvalidAlgorithmParameterException(
+ "Parameters must be an instance of "
+ + PKIXBuilderParameters.class.getName() + " or "
+ + ExtendedPKIXBuilderParameters.class.getName() + ".");
+ }
+
+ ExtendedPKIXBuilderParameters pkixParams = null;
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) params;
+ }
+ else
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
+ .getInstance((PKIXBuilderParameters) params);
+ }
+
+ Collection targets;
+ Iterator targetIter;
+ List certPathList = new ArrayList();
+ Set certPathSet = new HashSet();
+ X509Certificate cert;
+ Collection certs;
+ CertPath certPath = null;
+ Exception certPathException = null;
+
+ // search target certificates
+ CertSelector certSelect = pkixParams.getTargetCertConstraints();
+ if (certSelect == null)
+ {
+ throw new CertPathBuilderException("targetCertConstraints must be non-null for CertPath building");
+ }
+
+ try
+ {
+ targets = findCertificates(certSelect, pkixParams.getCertStores());
+ }
+ catch (CertStoreException e)
+ {
+ throw new CertPathBuilderException(e);
+ }
+
+ if (targets.isEmpty())
+ {
+ throw new CertPathBuilderException("no certificate found matching targetCertContraints");
+ }
+
+ CertificateFactory cFact;
+ CertPathValidator validator;
+
+ try
+ {
+ cFact = CertificateFactory.getInstance("X.509", "SC");
+ validator = CertPathValidator.getInstance("PKIX", "SC");
+ }
+ catch (Exception e)
+ {
+ throw new CertPathBuilderException("exception creating support classes: " + e);
+ }
+
+ //
+ // check all potential target certificates
+ targetIter = targets.iterator();
+ while (targetIter.hasNext())
+ {
+ cert = (X509Certificate)targetIter.next();
+ certPathList.clear();
+ certPathSet.clear();
+ while (cert != null)
+ {
+ // add cert to the certpath
+ certPathList.add(cert);
+ certPathSet.add(cert);
+
+ // check whether the issuer of <cert> is a TrustAnchor
+ if (findTrustAnchor(cert, pkixParams.getTrustAnchors()) != null)
+ {
+ try
+ {
+ certPath = cFact.generateCertPath(certPathList);
+
+ PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)validator.validate(certPath, pkixParams);
+
+ return new PKIXCertPathBuilderResult(certPath,
+ result.getTrustAnchor(),
+ result.getPolicyTree(),
+ result.getPublicKey());
+ }
+ catch (CertificateException ex)
+ {
+ certPathException = ex;
+ }
+ catch (CertPathValidatorException ex)
+ {
+ certPathException = ex;
+ }
+ // if validation failed go to next certificate
+ cert = null;
+ }
+ else
+ {
+ // try to get the issuer certificate from one
+ // of the CertStores
+ try
+ {
+ X509Certificate issuer = findIssuer(cert, pkixParams.getCertStores());
+ if (issuer.equals(cert))
+ {
+ cert = null;
+ }
+ else
+ {
+ cert = issuer;
+ // validation failed - circular path detected, go to next certificate
+ if (certPathSet.contains(cert))
+ {
+ cert = null;
+ }
+ }
+ }
+ catch (CertPathValidatorException ex)
+ {
+ certPathException = ex;
+ cert = null;
+ }
+ }
+ }
+ }
+
+ if (certPath != null)
+ {
+ throw new CertPathBuilderException("found certificate chain, but could not be validated", certPathException);
+ }
+
+ throw new CertPathBuilderException("unable to find certificate chain");
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the fiven X509 certificate.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ *
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ *
+ * @exception CertPathValidatorException if a TrustAnchor was
+ * found but the signature verificytion on the given certificate
+ * has thrown an exception. This Exception can be obtainted with
+ * <code>getCause()</code> method.
+ **/
+ final TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors)
+ throws CertPathBuilderException
+ {
+ Iterator iter = trustAnchors.iterator();
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+
+ try
+ {
+ certSelectX509.setSubject(PrincipalUtil.getIssuerX509Principal(cert).getEncoded());
+ }
+ catch (Exception ex)
+ {
+ throw new CertPathBuilderException("can't get trust anchor principal",null);
+ }
+
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X509Principal certIssuer = PrincipalUtil.getIssuerX509Principal(cert);
+ X509Principal caName = new X509Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (Exception ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ cert.verify(trustPublicKey);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new CertPathBuilderException("TrustAnchor found put certificate validation failed",invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ /**
+ * Return a Collection of all certificates found in the
+ * CertStore's that are matching the certSelect criteriums.
+ *
+ * @param certSelect a {@link CertSelector CertSelector}
+ * object that will be used to select the certificates
+ * @param certStores a List containing only {@link CertStore
+ * CertStore} objects. These are used to search for
+ * certificates
+ *
+ * @return a Collection of all found {@link Certificate Certificate}
+ * objects. May be empty but never <code>null</code>.
+ **/
+ private Collection findCertificates(
+ CertSelector certSelect,
+ List certStores)
+ throws CertStoreException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ CertStore certStore = (CertStore)iter.next();
+
+ certs.addAll(certStore.getCertificates(certSelect));
+ }
+
+ return certs;
+ }
+
+ /**
+ * Find the issuer certificate of the given certificate.
+ *
+ * @param cert the certificate hows issuer certificate should
+ * be found.
+ * @param certStores a list of <code>CertStore</code> object
+ * that will be searched
+ *
+ * @return then <code>X509Certificate</code> object containing
+ * the issuer certificate or <code>null</code> if not found
+ *
+ * @exception CertPathValidatorException if a TrustAnchor was
+ * found but the signature verificytion on the given certificate
+ * has thrown an exception. This Exception can be obtainted with
+ * <code>getCause()</code> method.
+ **/
+ private X509Certificate findIssuer(
+ X509Certificate cert,
+ List certStores)
+ throws CertPathValidatorException
+ {
+ Exception invalidKeyEx = null;
+ X509CertSelector certSelect = new X509CertSelector();
+ try
+ {
+ certSelect.setSubject(PrincipalUtil.getIssuerX509Principal(cert).getEncoded());
+ }
+ catch (Exception ex)
+ {
+ throw new CertPathValidatorException("Issuer not found", null, null, -1);
+ }
+
+ Iterator iter;
+ try
+ {
+ iter = findCertificates(certSelect, certStores).iterator();
+ }
+ catch (CertStoreException e)
+ {
+ throw new CertPathValidatorException(e);
+ }
+
+ X509Certificate issuer = null;
+ while (iter.hasNext() && issuer == null)
+ {
+ issuer = (X509Certificate)iter.next();
+ try
+ {
+ cert.verify(issuer.getPublicKey());
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ issuer = null;
+ }
+ }
+
+ if (issuer == null && invalidKeyEx == null)
+ {
+ throw new CertPathValidatorException("Issuer not found", null, null, -1);
+ }
+
+ if (issuer == null && invalidKeyEx != null)
+ {
+ throw new CertPathValidatorException("issuer found but certificate validation failed",invalidKeyEx,null,-1);
+ }
+
+ return issuer;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java
new file mode 100644
index 000000000..4dc75cf31
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -0,0 +1,431 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathParameters;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+import org.spongycastle.jce.cert.CertPathValidatorResult;
+import org.spongycastle.jce.cert.CertPathValidatorSpi;
+import org.spongycastle.jce.cert.PKIXCertPathChecker;
+import org.spongycastle.jce.cert.PKIXCertPathValidatorResult;
+import org.spongycastle.jce.cert.PKIXParameters;
+import org.spongycastle.jce.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.jce.X509Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+
+/**
+ * CertPathValidatorSpi implementation for X.509 Certificate validation � la RFC
+ * 3280.
+ */
+public class PKIXCertPathValidatorSpi
+ extends CertPathValidatorSpi
+{
+
+ public CertPathValidatorResult engineValidate(
+ CertPath certPath,
+ CertPathParameters params)
+ throws CertPathValidatorException,
+ InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXParameters))
+ {
+ throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName()
+ + " instance.");
+ }
+
+ ExtendedPKIXParameters paramsPKIX;
+ if (params instanceof ExtendedPKIXParameters)
+ {
+ paramsPKIX = (ExtendedPKIXParameters)params;
+ }
+ else
+ {
+ paramsPKIX = ExtendedPKIXParameters.getInstance((PKIXParameters)params);
+ }
+ if (paramsPKIX.getTrustAnchors() == null)
+ {
+ throw new InvalidAlgorithmParameterException(
+ "trustAnchors is null, this is not allowed for certification path validation.");
+ }
+
+ //
+ // 6.1.1 - inputs
+ //
+
+ //
+ // (a)
+ //
+ List certs = certPath.getCertificates();
+ int n = certs.size();
+
+ if (certs.isEmpty())
+ {
+ throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0);
+ }
+
+ //
+ // (b)
+ //
+ // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
+
+ //
+ // (c)
+ //
+ Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
+
+ //
+ // (d)
+ //
+ TrustAnchor trust;
+ try
+ {
+ trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
+ paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1);
+ }
+
+ if (trust == null)
+ {
+ throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
+ }
+
+ //
+ // (e), (f), (g) are part of the paramsPKIX object.
+ //
+ Iterator certIter;
+ int index = 0;
+ int i;
+ // Certificate for each interation of the validation loop
+ // Signature information for each iteration of the validation loop
+ //
+ // 6.1.2 - setup
+ //
+
+ //
+ // (a)
+ //
+ List[] policyNodes = new ArrayList[n + 1];
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ Set policySet = new HashSet();
+
+ policySet.add(RFC3280CertPathUtilities.ANY_POLICY);
+
+ PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(),
+ RFC3280CertPathUtilities.ANY_POLICY, false);
+
+ policyNodes[0].add(validPolicyTree);
+
+ //
+ // (b) and (c)
+ //
+ PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
+
+ // (d)
+ //
+ int explicitPolicy;
+ Set acceptablePolicies = new HashSet();
+
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ //
+ // (e)
+ //
+ int inhibitAnyPolicy;
+
+ if (paramsPKIX.isAnyPolicyInhibited())
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ //
+ // (f)
+ //
+ int policyMapping;
+
+ if (paramsPKIX.isPolicyMappingInhibited())
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ //
+ // (g), (h), (i), (j)
+ //
+ PublicKey workingPublicKey;
+ X509Principal workingIssuerName;
+
+ X509Certificate sign = trust.getTrustedCert();
+ try
+ {
+ if (sign != null)
+ {
+ workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+ workingPublicKey = sign.getPublicKey();
+ }
+ else
+ {
+ workingIssuerName = new X509Principal(trust.getCAName());
+ workingPublicKey = trust.getCAPublicKey();
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
+ -1);
+ }
+
+ AlgorithmIdentifier workingAlgId = null;
+ try
+ {
+ workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
+ }
+ DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
+
+ //
+ // (k)
+ //
+ int maxPathLength = n;
+
+ //
+ // 6.1.3
+ //
+
+ if (paramsPKIX.getTargetConstraints() != null
+ && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0)))
+ {
+ throw new ExtCertPathValidatorException(
+ "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
+ }
+
+ //
+ // initialize CertPathChecker's
+ //
+ List pathCheckers = paramsPKIX.getCertPathCheckers();
+ certIter = pathCheckers.iterator();
+ while (certIter.hasNext())
+ {
+ ((PKIXCertPathChecker) certIter.next()).init(false);
+ }
+
+ X509Certificate cert = null;
+
+ for (index = certs.size() - 1; index >= 0; index--)
+ {
+ // try
+ // {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialized the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate) certs.get(index);
+ boolean verificationAlreadyPerformed = (index == certs.size() - 1);
+
+ //
+ // 6.1.3
+ //
+
+ RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
+ verificationAlreadyPerformed, workingIssuerName, sign);
+
+ RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
+
+ validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies,
+ validPolicyTree, policyNodes, inhibitAnyPolicy);
+
+ validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree);
+
+ RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy);
+
+ //
+ // 6.1.4
+ //
+
+ if (i != n)
+ {
+ if (cert != null && cert.getVersion() == 1)
+ {
+ throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
+ certPath, index);
+ }
+
+ RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
+
+ validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree,
+ policyMapping);
+
+ RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator);
+
+ // (h)
+ explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy);
+ policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping);
+ inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy);
+
+ //
+ // (i)
+ //
+ explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy);
+ policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping);
+
+ // (j)
+ inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
+
+ // (k)
+ RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
+
+ // (l)
+ maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
+
+ // (m)
+ maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength);
+
+ // (n)
+ RFC3280CertPathUtilities.prepareNextCertN(certPath, index);
+
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+
+ // these extensions are handled by the algorithm
+ criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ // (o)
+ RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers);
+
+ // set signing certificate for next round
+ sign = cert;
+
+ // (c)
+ workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+
+ // (d)
+ try
+ {
+ workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
+ }
+
+ workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+ // (f)
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ // (e)
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ }
+
+ //
+ // 6.1.5 Wrap-up procedure
+ //
+
+ explicitPolicy = RFC3280CertPathUtilities.wrapupCertA(explicitPolicy, cert);
+
+ explicitPolicy = RFC3280CertPathUtilities.wrapupCertB(certPath, index + 1, explicitPolicy);
+
+ //
+ // (c) (d) and (e) are already done
+ //
+
+ //
+ // (f)
+ //
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ // these extensions are handled by the algorithm
+ criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ RFC3280CertPathUtilities.wrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
+
+ PKIXPolicyNode intersection = RFC3280CertPathUtilities.wrapupCertG(certPath, paramsPKIX, userInitialPolicySet,
+ index + 1, policyNodes, validPolicyTree, acceptablePolicies);
+
+ if ((explicitPolicy > 0) || (intersection != null))
+ {
+ return new PKIXCertPathValidatorResult(trust, intersection, cert.getPublicKey());
+ }
+
+ throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java
new file mode 100644
index 000000000..1a0b4e7b1
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java
@@ -0,0 +1,169 @@
+package org.spongycastle.jce.provider;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.jce.cert.PolicyNode;
+
+public class PKIXPolicyNode
+ implements PolicyNode
+{
+ protected List children;
+ protected int depth;
+ protected Set expectedPolicies;
+ protected PolicyNode parent;
+ protected Set policyQualifiers;
+ protected String validPolicy;
+ protected boolean critical;
+
+ /*
+ *
+ * CONSTRUCTORS
+ *
+ */
+
+ public PKIXPolicyNode(
+ List _children,
+ int _depth,
+ Set _expectedPolicies,
+ PolicyNode _parent,
+ Set _policyQualifiers,
+ String _validPolicy,
+ boolean _critical)
+ {
+ children = _children;
+ depth = _depth;
+ expectedPolicies = _expectedPolicies;
+ parent = _parent;
+ policyQualifiers = _policyQualifiers;
+ validPolicy = _validPolicy;
+ critical = _critical;
+ }
+
+ public void addChild(
+ PKIXPolicyNode _child)
+ {
+ children.add(_child);
+ _child.setParent(this);
+ }
+
+ public Iterator getChildren()
+ {
+ return children.iterator();
+ }
+
+ public int getDepth()
+ {
+ return depth;
+ }
+
+ public Set getExpectedPolicies()
+ {
+ return expectedPolicies;
+ }
+
+ public PolicyNode getParent()
+ {
+ return parent;
+ }
+
+ public Set getPolicyQualifiers()
+ {
+ return policyQualifiers;
+ }
+
+ public String getValidPolicy()
+ {
+ return validPolicy;
+ }
+
+ public boolean hasChildren()
+ {
+ return !children.isEmpty();
+ }
+
+ public boolean isCritical()
+ {
+ return critical;
+ }
+
+ public void removeChild(PKIXPolicyNode _child)
+ {
+ children.remove(_child);
+ }
+
+ public void setCritical(boolean _critical)
+ {
+ critical = _critical;
+ }
+
+ public void setParent(PKIXPolicyNode _parent)
+ {
+ parent = _parent;
+ }
+
+ public String toString()
+ {
+ return toString("");
+ }
+
+ public String toString(String _indent)
+ {
+ StringBuffer _buf = new StringBuffer();
+ _buf.append(_indent);
+ _buf.append(validPolicy);
+ _buf.append(" {\n");
+
+ for(int i = 0; i < children.size(); i++)
+ {
+ _buf.append(((PKIXPolicyNode)children.get(i)).toString(_indent + " "));
+ }
+
+ _buf.append(_indent);
+ _buf.append("}\n");
+ return _buf.toString();
+ }
+
+ public Object clone()
+ {
+ return copy();
+ }
+
+ public PKIXPolicyNode copy()
+ {
+ Set _expectedPolicies = new HashSet();
+ Iterator _iter = expectedPolicies.iterator();
+ while (_iter.hasNext())
+ {
+ _expectedPolicies.add(new String((String)_iter.next()));
+ }
+
+ Set _policyQualifiers = new HashSet();
+ _iter = policyQualifiers.iterator();
+ while (_iter.hasNext())
+ {
+ _policyQualifiers.add(new String((String)_iter.next()));
+ }
+
+ PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(),
+ depth,
+ _expectedPolicies,
+ null,
+ _policyQualifiers,
+ new String(validPolicy),
+ critical);
+
+ _iter = children.iterator();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy();
+ _child.setParent(_node);
+ _node.addChild(_child);
+ }
+
+ return _node;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java
new file mode 100644
index 000000000..74efc9a99
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java
@@ -0,0 +1,72 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Permission;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfigurationPermission;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+public class ProviderUtil
+{
+ private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ "SC", ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+ private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
+ "SC", ConfigurableProvider.EC_IMPLICITLY_CA);
+
+ private static ThreadLocal threadSpec = new ThreadLocal();
+ private static volatile ECParameterSpec ecImplicitCaParams;
+
+ static void setParameter(String parameterName, Object parameter)
+ {
+ SecurityManager securityManager = System.getSecurityManager();
+
+ if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+ {
+ ECParameterSpec curveSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
+ }
+
+ curveSpec = (ECParameterSpec)parameter;
+
+ threadSpec.set(curveSpec);
+ }
+ else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_PERMISSION);
+ }
+
+ ecImplicitCaParams = (ECParameterSpec)parameter;
+ }
+ }
+
+ public static ECParameterSpec getEcImplicitlyCa()
+ {
+ ECParameterSpec spec = (ECParameterSpec)threadSpec.get();
+
+ if (spec != null)
+ {
+ return spec;
+ }
+
+ return ecImplicitCaParams;
+ }
+
+ static int getReadLimit(InputStream in)
+ throws IOException
+ {
+ if (in instanceof ByteArrayInputStream)
+ {
+ return in.available();
+ }
+
+ return Integer.MAX_VALUE;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java
new file mode 100644
index 000000000..17efca7ec
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -0,0 +1,2581 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathBuilder;
+import org.spongycastle.jce.cert.CertPathBuilderException;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import org.spongycastle.jce.cert.PKIXCertPathChecker;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509Extension;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.GeneralSubtree;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.NameConstraints;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+
+public class RFC3280CertPathUtilities
+{
+ private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ /**
+ * If the complete CRL includes an issuing distribution point (IDP) CRL
+ * extension check the following:
+ * <p/>
+ * (i) If the distribution point name is present in the IDP CRL extension
+ * and the distribution field is present in the DP, then verify that one of
+ * the names in the IDP matches one of the names in the DP. If the
+ * distribution point name is present in the IDP CRL extension and the
+ * distribution field is omitted from the DP, then verify that one of the
+ * names in the IDP matches one of the names in the cRLIssuer field of the
+ * DP.
+ * </p>
+ * <p/>
+ * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate does not include the basic
+ * constraints extension with the cA boolean asserted.
+ * </p>
+ * <p/>
+ * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate includes the basic constraints
+ * extension with the cA boolean asserted.
+ * </p>
+ * <p/>
+ * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+ * </p>
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate.
+ * @param crl The CRL.
+ * @throws AnnotatedException if one of the conditions is not met or an error occurs.
+ */
+ protected static void processCRLB2(
+ DistributionPoint dp,
+ Object cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+ // (b) (2) (i)
+ // distribution point name is present
+ if (idp != null)
+ {
+ if (idp.getDistributionPoint() != null)
+ {
+ // make list of names
+ DistributionPointName dpName = IssuingDistributionPoint.getInstance(idp).getDistributionPoint();
+ List names = new ArrayList();
+
+ if (dpName.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ names.add(genNames[j]);
+ }
+ }
+ if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ try
+ {
+ Enumeration e = ASN1Sequence.getInstance(
+ ASN1Sequence.fromByteArray(CertPathValidatorUtilities.getIssuerPrincipal(crl)
+ .getEncoded())).getObjects();
+ while (e.hasMoreElements())
+ {
+ vec.add((ASN1Encodable)e.nextElement());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Could not read CRL issuer.", e);
+ }
+ vec.add(dpName.getName());
+ names.add(new GeneralName(X509Name.getInstance(new DERSequence(vec))));
+ }
+ boolean matches = false;
+ // verify that one of the names in the IDP matches one
+ // of the names in the DP.
+ if (dp.getDistributionPoint() != null)
+ {
+ dpName = dp.getDistributionPoint();
+ GeneralName[] genNames = null;
+ if (dpName.getType() == DistributionPointName.FULL_NAME)
+ {
+ genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+ }
+ if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ {
+ if (dp.getCRLIssuer() != null)
+ {
+ genNames = dp.getCRLIssuer().getNames();
+ }
+ else
+ {
+ genNames = new GeneralName[1];
+ try
+ {
+ genNames[0] = new GeneralName(new X509Name(
+ (ASN1Sequence)ASN1Sequence.fromByteArray(CertPathValidatorUtilities
+ .getEncodedIssuerPrincipal(cert).getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Could not read certificate issuer.", e);
+ }
+ }
+ for (int j = 0; j < genNames.length; j++)
+ {
+ Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().toASN1Primitive()).getObjects();
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ while (e.hasMoreElements())
+ {
+ vec.add((ASN1Encodable)e.nextElement());
+ }
+ vec.add(dpName.getName());
+ genNames[j] = new GeneralName(new X509Name(new DERSequence(vec)));
+ }
+ }
+ if (genNames != null)
+ {
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (names.contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ }
+ if (!matches)
+ {
+ throw new AnnotatedException(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ // verify that one of the names in
+ // the IDP matches one of the names in the cRLIssuer field of
+ // the DP
+ else
+ {
+ if (dp.getCRLIssuer() == null)
+ {
+ throw new AnnotatedException("Either the cRLIssuer or the distributionPoint field must "
+ + "be contained in DistributionPoint.");
+ }
+ GeneralName[] genNames = dp.getCRLIssuer().getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (names.contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ if (!matches)
+ {
+ throw new AnnotatedException(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ }
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue((X509Extension)cert,
+ BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Basic constraints extension could not be decoded.", e);
+ }
+
+ if (cert instanceof X509Certificate)
+ {
+ // (b) (2) (ii)
+ if (idp.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+ {
+ throw new AnnotatedException("CA Cert CRL only contains user certificates.");
+ }
+
+ // (b) (2) (iii)
+ if (idp.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+ {
+ throw new AnnotatedException("End CRL only contains CA certificates.");
+ }
+ }
+
+ // (b) (2) (iv)
+ if (idp.onlyContainsAttributeCerts())
+ {
+ throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted.");
+ }
+ }
+ }
+
+ /**
+ * If the DP includes cRLIssuer, then verify that the issuer field in the
+ * complete CRL matches cRLIssuer in the DP and that the complete CRL
+ * contains an issuing distribution point extension with the indirectCRL
+ * boolean asserted. Otherwise, verify that the CRL issuer matches the
+ * certificate issuer.
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate ot attribute certificate.
+ * @param crl The CRL for <code>cert</code>.
+ * @throws AnnotatedException if one of the above conditions does not apply or an error
+ * occurs.
+ */
+ protected static void processCRLB1(
+ DistributionPoint dp,
+ Object cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ ASN1Primitive idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+ boolean isIndirect = false;
+ if (idp != null)
+ {
+ if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL())
+ {
+ isIndirect = true;
+ }
+ }
+ byte[] issuerBytes = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded();
+
+ boolean matchIssuer = false;
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (Arrays.areEqual(genNames[j].getName().toASN1Primitive().getEncoded(), issuerBytes))
+ {
+ matchIssuer = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.", e);
+ }
+ }
+ }
+ if (matchIssuer && !isIndirect)
+ {
+ throw new AnnotatedException("Distribution point contains cRLIssuer field but CRL is not indirect.");
+ }
+ if (!matchIssuer)
+ {
+ throw new AnnotatedException("CRL issuer of CRL does not match CRL issuer of distribution point.");
+ }
+ }
+ else
+ {
+ if (CertPathValidatorUtilities.getIssuerPrincipal(crl).equals(
+ CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)))
+ {
+ matchIssuer = true;
+ }
+ }
+ if (!matchIssuer)
+ {
+ throw new AnnotatedException("Cannot find matching CRL issuer for certificate.");
+ }
+ }
+
+ protected static ReasonsMask processCRLD(
+ X509CRL crl,
+ DistributionPoint dp)
+ throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+ // (d) (1)
+ if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null)
+ {
+ return new ReasonsMask(dp.getReasons()).intersect(new ReasonsMask(idp.getOnlySomeReasons()));
+ }
+ // (d) (4)
+ if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null)
+ {
+ return ReasonsMask.allReasons;
+ }
+ // (d) (2) and (d)(3)
+ return (dp.getReasons() == null
+ ? ReasonsMask.allReasons
+ : new ReasonsMask(dp.getReasons())).intersect(idp == null
+ ? ReasonsMask.allReasons
+ : new ReasonsMask(idp.getOnlySomeReasons()));
+
+ }
+
+ public static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+
+ public static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+
+ public static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+
+ public static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+
+ public static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+
+ public static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+
+ public static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+
+ public static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+
+ public static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+
+ public static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+
+ public static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+
+ public static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ public static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+
+ public static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ public static final String ANY_POLICY = "2.5.29.32.0";
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+
+ protected static final int CRL_SIGN = 6;
+
+ /**
+ * Obtain and validate the certification path for the complete CRL issuer.
+ * If a key usage extension is present in the CRL issuer's certificate,
+ * verify that the cRLSign bit is set.
+ *
+ * @param crl CRL which contains revocation information for the certificate
+ * <code>cert</code>.
+ * @param cert The attribute certificate or certificate to check if it is
+ * revoked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param paramsPKIX paramsPKIX PKIX parameters.
+ * @param certPathCerts The certificates on the certification path.
+ * @return A <code>Set</code> with all keys of possible CRL issuer
+ * certificates.
+ * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+ * some error occurs.
+ */
+ protected static Set processCRLF(
+ X509CRL crl,
+ Object cert,
+ X509Certificate defaultCRLSignCert,
+ PublicKey defaultCRLSignKey,
+ ExtendedPKIXParameters paramsPKIX,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ // (f)
+
+ // get issuer from CRL
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ try
+ {
+ byte[] issuerPrincipal = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded();
+ selector.setSubject(issuerPrincipal);
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e);
+ }
+
+ // get CRL signing certs
+ Collection coll;
+ try
+ {
+ coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getStores());
+ coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getAdditionalStores()));
+ coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate for CRL cannot be searched.", e);
+ }
+
+ coll.add(defaultCRLSignCert);
+
+ Iterator cert_it = coll.iterator();
+
+ List validCerts = new ArrayList();
+ List validKeys = new ArrayList();
+
+ while (cert_it.hasNext())
+ {
+ X509Certificate signingCert = (X509Certificate)cert_it.next();
+
+ /*
+ * CA of the certificate, for which this CRL is checked, has also
+ * signed CRL, so skip the path validation, because is already done
+ */
+ if (signingCert.equals(defaultCRLSignCert))
+ {
+ validCerts.add(signingCert);
+ validKeys.add(defaultCRLSignKey);
+ continue;
+ }
+ try
+ {
+ CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ selector = new X509CertStoreSelector();
+ selector.setCertificate(signingCert);
+ ExtendedPKIXParameters temp = (ExtendedPKIXParameters)paramsPKIX.clone();
+ temp.setTargetCertConstraints(selector);
+ ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters)ExtendedPKIXBuilderParameters
+ .getInstance(temp);
+ /*
+ * if signingCert is placed not higher on the cert path a
+ * dependency loop results. CRL for cert is checked, but
+ * signingCert is needed for checking the CRL which is dependent
+ * on checking cert because it is higher in the cert path and so
+ * signing signingCert transitively. so, revocation is disabled,
+ * forgery attacks of the CRL are detected in this outer loop
+ * for all other it must be enabled to prevent forgery attacks
+ */
+ if (certPathCerts.contains(signingCert))
+ {
+ params.setRevocationEnabled(false);
+ }
+ else
+ {
+ params.setRevocationEnabled(true);
+ }
+ List certs = builder.build(params).getCertPath().getCertificates();
+ validCerts.add(signingCert);
+ validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0));
+ }
+ catch (CertPathBuilderException e)
+ {
+ throw new AnnotatedException("Internal error.", e);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new AnnotatedException("Public key of issuer certificate of CRL could not be retrieved.", e);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ Set checkKeys = new HashSet();
+
+ AnnotatedException lastException = null;
+ for (int i = 0; i < validCerts.size(); i++)
+ {
+ X509Certificate signCert = (X509Certificate)validCerts.get(i);
+ boolean[] keyusage = signCert.getKeyUsage();
+
+ if (keyusage != null && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+ {
+ lastException = new AnnotatedException(
+ "Issuer certificate key usage extension does not permit CRL signing.");
+ }
+ else
+ {
+ checkKeys.add(validKeys.get(i));
+ }
+ }
+
+ if (checkKeys.isEmpty() && lastException == null)
+ {
+ throw new AnnotatedException("Cannot find a valid issuer certificate.");
+ }
+ if (checkKeys.isEmpty() && lastException != null)
+ {
+ throw lastException;
+ }
+
+ return checkKeys;
+ }
+
+ protected static PublicKey processCRLG(
+ X509CRL crl,
+ Set keys)
+ throws AnnotatedException
+ {
+ Exception lastException = null;
+ for (Iterator it = keys.iterator(); it.hasNext();)
+ {
+ PublicKey key = (PublicKey)it.next();
+ try
+ {
+ crl.verify(key);
+ return key;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ throw new AnnotatedException("Cannot verify CRL.", lastException);
+ }
+
+ protected static X509CRL processCRLH(
+ Set deltacrls,
+ PublicKey key)
+ throws AnnotatedException
+ {
+ Exception lastException = null;
+
+ for (Iterator it = deltacrls.iterator(); it.hasNext();)
+ {
+ X509CRL crl = (X509CRL)it.next();
+ try
+ {
+ crl.verify(key);
+ return crl;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (lastException != null)
+ {
+ throw new AnnotatedException("Cannot verify delta CRL.", lastException);
+ }
+ return null;
+ }
+
+ protected static Set processCRLA1i(
+ Date currentDate,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ Set set = new HashSet();
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ CRLDistPoint freshestCRL = null;
+ try
+ {
+ freshestCRL = CRLDistPoint
+ .getInstance(CertPathValidatorUtilities.getExtensionValue(cert, FRESHEST_CRL));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Freshest CRL extension could not be decoded from certificate.", e);
+ }
+ if (freshestCRL == null)
+ {
+ try
+ {
+ freshestCRL = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ FRESHEST_CRL));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Freshest CRL extension could not be decoded from CRL.", e);
+ }
+ }
+ if (freshestCRL != null)
+ {
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "No new delta CRL locations could be added from Freshest CRL extension.", e);
+ }
+ // get delta CRL(s)
+ try
+ {
+ set.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+ }
+ }
+ }
+ return set;
+ }
+
+ protected static Set[] processCRLA1ii(
+ Date currentDate,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ Set deltaSet = new HashSet();
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ crlselect.setCertificateChecking(cert);
+
+ try
+ {
+ crlselect.addIssuerName(PrincipalUtil.getIssuerX509Principal(crl).getEncoded());
+ }
+ catch (CRLException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL." + e, e);
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL." + e, e);
+ }
+
+ crlselect.setCompleteCRLEnabled(true);
+ Set completeSet = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRL(s)
+ try
+ {
+ deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+ }
+ }
+ return new Set[]
+ {
+ completeSet,
+ deltaSet};
+ }
+
+
+
+ /**
+ * If use-deltas is set, verify the issuer and scope of the delta CRL.
+ *
+ * @param deltaCRL The delta CRL.
+ * @param completeCRL The complete CRL.
+ * @param pkixParams The PKIX paramaters.
+ * @throws AnnotatedException if an exception occurs.
+ */
+ protected static void processCRLC(
+ X509CRL deltaCRL,
+ X509CRL completeCRL,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (deltaCRL == null)
+ {
+ return;
+ }
+ IssuingDistributionPoint completeidp = null;
+ try
+ {
+ completeidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+ completeCRL, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+
+ if (pkixParams.isUseDeltasEnabled())
+ {
+ // (c) (1)
+ try
+ {
+ if (!PrincipalUtil.getIssuerX509Principal(deltaCRL).equals(PrincipalUtil.getIssuerX509Principal(completeCRL)))
+ {
+ throw new AnnotatedException("Complete CRL issuer does not match delta CRL issuer.");
+ }
+ }
+ catch (CRLException e)
+ {
+ throw new AnnotatedException(
+ "Cannot extract issuer from CRL.", e);
+ }
+
+ // (c) (2)
+ IssuingDistributionPoint deltaidp = null;
+ try
+ {
+ deltaidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+ deltaCRL, ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension from delta CRL could not be decoded.", e);
+ }
+
+ boolean match = false;
+ if (completeidp == null)
+ {
+ if (deltaidp == null)
+ {
+ match = true;
+ }
+ }
+ else
+ {
+ if (completeidp.equals(deltaidp))
+ {
+ match = true;
+ }
+ }
+ if (!match)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension from delta CRL and complete CRL does not match.");
+ }
+
+ // (c) (3)
+ ASN1Primitive completeKeyIdentifier = null;
+ try
+ {
+ completeKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+ completeCRL, AUTHORITY_KEY_IDENTIFIER);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Authority key identifier extension could not be extracted from complete CRL.", e);
+ }
+
+ ASN1Primitive deltaKeyIdentifier = null;
+ try
+ {
+ deltaKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+ deltaCRL, AUTHORITY_KEY_IDENTIFIER);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Authority key identifier extension could not be extracted from delta CRL.", e);
+ }
+
+ if (completeKeyIdentifier == null)
+ {
+ throw new AnnotatedException("CRL authority key identifier is null.");
+ }
+
+ if (deltaKeyIdentifier == null)
+ {
+ throw new AnnotatedException("Delta CRL authority key identifier is null.");
+ }
+
+ if (!completeKeyIdentifier.equals(deltaKeyIdentifier))
+ {
+ throw new AnnotatedException(
+ "Delta CRL authority key identifier does not match complete CRL authority key identifier.");
+ }
+ }
+ }
+
+ protected static void processCRLI(
+ Date validDate,
+ X509CRL deltacrl,
+ Object cert,
+ CertStatus certStatus,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (pkixParams.isUseDeltasEnabled() && deltacrl != null)
+ {
+ CertPathValidatorUtilities.getCertStatus(validDate, deltacrl, cert, certStatus);
+ }
+ }
+
+ protected static void processCRLJ(
+ Date validDate,
+ X509CRL completecrl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ CertPathValidatorUtilities.getCertStatus(validDate, completecrl, cert, certStatus);
+ }
+ }
+
+ protected static PKIXPolicyNode prepareCertB(
+ CertPath certPath,
+ int index,
+ List[] policyNodes,
+ PKIXPolicyNode validPolicyTree,
+ int policyMapping)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ // (b)
+ //
+ ASN1Sequence pm = null;
+ try
+ {
+ pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_MAPPINGS));
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+ index);
+ }
+ PKIXPolicyNode _validPolicyTree = validPolicyTree;
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence)pm;
+ Map m_idp = new HashMap();
+ Set s_idp = new HashSet();
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+ String id_p = ((DERObjectIdentifier)mapping.getObjectAt(0)).getId();
+ String sd_p = ((DERObjectIdentifier)mapping.getObjectAt(1)).getId();
+ Set tmp;
+
+ if (!m_idp.containsKey(id_p))
+ {
+ tmp = new HashSet();
+ tmp.add(sd_p);
+ m_idp.put(id_p, tmp);
+ s_idp.add(id_p);
+ }
+ else
+ {
+ tmp = (Set)m_idp.get(id_p);
+ tmp.add(sd_p);
+ }
+ }
+
+ Iterator it_idp = s_idp.iterator();
+ while (it_idp.hasNext())
+ {
+ String id_p = (String)it_idp.next();
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Certificate policies extension could not be decoded.", e, certPath, index);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new CertPathValidatorException(
+ "Policy information could not be decoded.", ex, certPath, index);
+ }
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = CertPathValidatorUtilities
+ .getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be decoded.", ex, certPath,
+ index);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(new ArrayList(), i, (Set)m_idp
+ .get(id_p), p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(
+ _validPolicyTree, policyNodes, node2);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return _validPolicyTree;
+ }
+
+ protected static void prepareNextCertA(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ //
+ // (a) check the policy mappings
+ //
+ ASN1Sequence pm = null;
+ try
+ {
+ pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_MAPPINGS));
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+ index);
+ }
+ if (pm != null)
+ {
+ ASN1Sequence mappings = pm;
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ DERObjectIdentifier issuerDomainPolicy = null;
+ DERObjectIdentifier subjectDomainPolicy = null;
+ try
+ {
+ ASN1Sequence mapping = DERSequence.getInstance(mappings.getObjectAt(j));
+
+ issuerDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(0));
+ subjectDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(1));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension contents could not be decoded.",
+ e, certPath, index);
+ }
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(issuerDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy", null, certPath, index);
+ }
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(subjectDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy,", null, certPath, index);
+ }
+ }
+ }
+ }
+
+ protected static void processCertF(
+ CertPath certPath,
+ int index,
+ PKIXPolicyNode validPolicyTree,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ //
+ // (f)
+ //
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ throw new ExtCertPathValidatorException("No valid policy tree found when one expected.", null, certPath,
+ index);
+ }
+ }
+
+ protected static PKIXPolicyNode processCertE(
+ CertPath certPath,
+ int index,
+ PKIXPolicyNode validPolicyTree)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (e)
+ //
+ ASN1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+ return validPolicyTree;
+ }
+
+ protected static void processCertBC(
+ CertPath certPath,
+ int index,
+ PKIXNameConstraintValidator nameConstraintValidator)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (b), (c) permitted and excluded subtree checking.
+ //
+ if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n)))
+ {
+ X509Principal principal = CertPathValidatorUtilities.getSubjectPrincipal(cert);
+ ASN1InputStream aIn = new ASN1InputStream(principal.getEncoded());
+ ASN1Sequence dns;
+
+ try
+ {
+ dns = DERSequence.getInstance(aIn.readObject());
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Exception extracting subject name when checking subtrees.", e,
+ certPath, index);
+ }
+
+ try
+ {
+ nameConstraintValidator.checkPermittedDN(dns);
+ nameConstraintValidator.checkExcludedDN(dns);
+ }
+ catch (PKIXNameConstraintValidatorException e)
+ {
+ throw new CertPathValidatorException("Subtree check for certificate subject failed.", e, certPath,
+ index);
+ }
+
+ GeneralNames altName = null;
+ try
+ {
+ altName = GeneralNames.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME));
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Subject alternative name extension could not be decoded.", e,
+ certPath, index);
+ }
+ Vector emails = new X509Name(dns).getValues(X509Name.EmailAddress);
+ for (Enumeration e = emails.elements(); e.hasMoreElements();)
+ {
+ String email = (String)e.nextElement();
+ GeneralName emailAsGeneralName = new GeneralName(GeneralName.rfc822Name, email);
+ try
+ {
+ nameConstraintValidator.checkPermitted(emailAsGeneralName);
+ nameConstraintValidator.checkExcluded(emailAsGeneralName);
+ }
+ catch (PKIXNameConstraintValidatorException ex)
+ {
+ throw new CertPathValidatorException(
+ "Subtree check for certificate subject alternative email failed.", ex, certPath, index);
+ }
+ }
+ if (altName != null)
+ {
+ GeneralName[] genNames = null;
+ try
+ {
+ genNames = altName.getNames();
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Subject alternative name contents could not be decoded.", e,
+ certPath, index);
+ }
+ for (int j = 0; j < genNames.length; j++)
+ {
+
+ try
+ {
+ nameConstraintValidator.checkPermitted(genNames[j]);
+ nameConstraintValidator.checkExcluded(genNames[j]);
+ }
+ catch (PKIXNameConstraintValidatorException e)
+ {
+ throw new CertPathValidatorException(
+ "Subtree check for certificate subject alternative name failed.", e, certPath, index);
+ }
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode processCertD(
+ CertPath certPath,
+ int index,
+ Set acceptablePolicies,
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ int inhibitAnyPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (d) policy Information checking against initial policy and
+ // policy mapping
+ //
+ ASN1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies != null && validPolicyTree != null)
+ {
+ //
+ // (d) (1)
+ //
+ Enumeration e = certPolicies.getObjects();
+ Set pols = new HashSet();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+ DERObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+ pols.add(pOid.getId());
+
+ if (!RFC3280CertPathUtilities.ANY_POLICY.equals(pOid.getId()))
+ {
+ Set pq = null;
+ try
+ {
+ pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info set could not be build.", ex,
+ certPath, index);
+ }
+
+ boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies.isEmpty() || acceptablePolicies.contains(RFC3280CertPathUtilities.ANY_POLICY))
+ {
+ acceptablePolicies.clear();
+ acceptablePolicies.addAll(pols);
+ }
+ else
+ {
+ Iterator it = acceptablePolicies.iterator();
+ Set t1 = new HashSet();
+
+ while (it.hasNext())
+ {
+ Object o = it.next();
+
+ if (pols.contains(o))
+ {
+ t1.add(o);
+ }
+ }
+ acceptablePolicies.clear();
+ acceptablePolicies.addAll(t1);
+ }
+
+ //
+ // (d) (2)
+ //
+ if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert)))
+ {
+ e = certPolicies.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+ {
+ Set _apq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+ List _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k);
+
+ Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+ while (_policySetIter.hasNext())
+ {
+ Object _tmp = _policySetIter.next();
+
+ String _policy;
+ if (_tmp instanceof String)
+ {
+ _policy = (String)_tmp;
+ }
+ else if (_tmp instanceof DERObjectIdentifier)
+ {
+ _policy = ((DERObjectIdentifier)_tmp).getId();
+ }
+ else
+ {
+ continue;
+ }
+
+ boolean _found = false;
+ Iterator _childrenIter = _node.getChildren();
+
+ while (_childrenIter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next();
+
+ if (_policy.equals(_child.getValidPolicy()))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ Set _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.add(_policy);
+
+ PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(), i,
+ _newChildExpectedPolicies, _node, _apq, _policy, false);
+ _node.addChild(_newChild);
+ policyNodes[i].add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ PKIXPolicyNode _validPolicyTree = validPolicyTree;
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(_validPolicyTree, policyNodes,
+ node);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensionOids != null)
+ {
+ boolean critical = criticalExtensionOids.contains(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+
+ List nodes = policyNodes[i];
+ for (int j = 0; j < nodes.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j);
+ node.setCritical(critical);
+ }
+ }
+ return _validPolicyTree;
+ }
+ return null;
+ }
+
+ protected static void processCertA(
+ CertPath certPath,
+ ExtendedPKIXParameters paramsPKIX,
+ int index,
+ PublicKey workingPublicKey,
+ boolean verificationAlreadyPerformed,
+ X509Principal workingIssuerName,
+ X509Certificate sign)
+ throws ExtCertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (a) verify
+ //
+ if (!verificationAlreadyPerformed)
+ {
+ try
+ {
+ // (a) (1)
+ //
+ CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
+ paramsPKIX.getSigProvider());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+ }
+ }
+
+ try
+ {
+ // (a) (2)
+ //
+ cert.checkValidity(CertPathValidatorUtilities
+ .getValidCertDateFromValidityModel(paramsPKIX, certPath, index));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
+ }
+
+ //
+ // (a) (3)
+ //
+ if (paramsPKIX.isRevocationEnabled())
+ {
+ try
+ {
+ checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX,
+ certPath, index), sign, workingPublicKey, certs);
+ }
+ catch (AnnotatedException e)
+ {
+ Throwable cause = e;
+ if (null != e.getCause())
+ {
+ cause = e.getCause();
+ }
+ throw new ExtCertPathValidatorException(e.getMessage(), cause, certPath, index);
+ }
+ }
+
+ //
+ // (a) (4) name chaining
+ //
+ if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
+ {
+ throw new ExtCertPathValidatorException("IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)
+ + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
+ certPath, index);
+ }
+ }
+
+ protected static int prepareNextCertI1(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (i)
+ //
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ try
+ {
+
+ ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+ if (constraint.getTagNo() == 0)
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < explicitPolicy)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+ e, certPath, index);
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static int prepareNextCertI2(
+ CertPath certPath,
+ int index,
+ int policyMapping)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (i)
+ //
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ try
+ {
+ ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+ if (constraint.getTagNo() == 1)
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < policyMapping)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+ e, certPath, index);
+ }
+ }
+ }
+ return policyMapping;
+ }
+
+ protected static void prepareNextCertG(
+ CertPath certPath,
+ int index,
+ PKIXNameConstraintValidator nameConstraintValidator)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (g) handle the name constraints extension
+ //
+ NameConstraints nc = null;
+ try
+ {
+ ASN1Sequence ncSeq = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.NAME_CONSTRAINTS));
+ if (ncSeq != null)
+ {
+ nc = NameConstraints.getInstance(ncSeq);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Name constraints extension could not be decoded.", e, certPath,
+ index);
+ }
+ if (nc != null)
+ {
+
+ //
+ // (g) (1) permitted subtrees
+ //
+ GeneralSubtree[] permitted = nc.getPermittedSubtrees();
+ if (permitted != null)
+ {
+ try
+ {
+ nameConstraintValidator.intersectPermittedSubtree(permitted);
+ }
+ catch (Exception ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ GeneralSubtree[] excluded = nc.getExcludedSubtrees();
+ if (excluded != null)
+ {
+ for (int i = 0; i != excluded.length; i++)
+ try
+ {
+ nameConstraintValidator.addExcludedSubtree(excluded[i]);
+ }
+ catch (Exception ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks a distribution point for revocation information for the
+ * certificate <code>cert</code>.
+ *
+ * @param dp The distribution point to consider.
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param certStatus The current certificate revocation status.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ private static void checkCRL(
+ DistributionPoint dp,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate defaultCRLSignCert,
+ PublicKey defaultCRLSignKey,
+ CertStatus certStatus,
+ ReasonsMask reasonMask,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ Date currentDate = new Date(System.currentTimeMillis());
+ if (validDate.getTime() > currentDate.getTime())
+ {
+ throw new AnnotatedException("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPKIXParameters and are in
+ * getAdditionalStore()
+ */
+
+ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, cert, currentDate, paramsPKIX);
+ boolean validCrlFound = false;
+ AnnotatedException lastException = null;
+ Iterator crl_iter = crls.iterator();
+
+ while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons())
+ {
+ try
+ {
+ X509CRL crl = (X509CRL)crl_iter.next();
+
+ // (d)
+ ReasonsMask interimReasonsMask = RFC3280CertPathUtilities.processCRLD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.hasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ Set keys = RFC3280CertPathUtilities.processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey,
+ paramsPKIX, certPathCerts);
+ // (g)
+ PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys);
+
+ X509CRL deltaCRL = null;
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRLs
+ Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs, key);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL validity time
+ */
+
+ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (cert.getNotAfter().getTime() < crl.getThisUpdate().getTime())
+ {
+ throw new AnnotatedException("No valid CRL for current time found.");
+ }
+ }
+
+ RFC3280CertPathUtilities.processCRLB1(dp, cert, crl);
+
+ // (b) (2)
+ RFC3280CertPathUtilities.processCRLB2(dp, cert, crl);
+
+ // (c)
+ RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL, cert, certStatus, paramsPKIX);
+
+ // (j)
+ RFC3280CertPathUtilities.processCRLJ(validDate, crl, cert, certStatus);
+
+ // (k)
+ if (certStatus.getCertStatus() == CRLReason.removeFromCRL)
+ {
+ certStatus.setCertStatus(CertStatus.UNREVOKED);
+ }
+
+ // update reasons mask
+ reasonMask.addReasons(interimReasonsMask);
+
+ Set criticalExtensions = crl.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId());
+ criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId());
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new AnnotatedException("CRL contains unsupported critical extensions.");
+ }
+ }
+
+ if (deltaCRL != null)
+ {
+ criticalExtensions = deltaCRL.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId());
+ criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId());
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new AnnotatedException("Delta CRL contains unsupported critical extension.");
+ }
+ }
+ }
+
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+
+ /**
+ * Checks a certificate if it is revoked.
+ *
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param sign The issuer certificate of the certificate <code>cert</code>.
+ * @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ protected static void checkCRLs(
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate sign,
+ PublicKey workingPublicKey,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ AnnotatedException lastException = null;
+ CRLDistPoint crldp = null;
+ try
+ {
+ crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("CRL distribution point extension could not be read.", e);
+ }
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ boolean validCrlFound = false;
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Distribution points could not be read.", e);
+ }
+ if (dps != null)
+ {
+ for (int i = 0; i < dps.length && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons(); i++)
+ {
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone();
+ try
+ {
+ checkCRL(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the process
+ * above with any available CRLs not specified in a distribution point
+ * but issued by the certificate issuer.
+ */
+
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons())
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer fields
+ * omitted and a distribution point name of the certificate
+ * issuer.
+ */
+ ASN1Primitive issuer = null;
+ try
+ {
+ issuer = new ASN1InputStream(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded())
+ .readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuer from certificate for CRL could not be reencoded.", e);
+ }
+ DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.directoryName, issuer))), null, null);
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone();
+ checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask,
+ certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ if (lastException instanceof AnnotatedException)
+ {
+ throw lastException;
+ }
+
+ throw new AnnotatedException("No valid CRL found.", lastException);
+ }
+ if (certStatus.getCertStatus() != CertStatus.UNREVOKED)
+ {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
+ df.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String message = "Certificate revocation after " + df.format(certStatus.getRevocationDate());
+ message += ", reason: " + crlReasons[certStatus.getCertStatus()];
+ throw new AnnotatedException(message);
+ }
+ if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ certStatus.setCertStatus(CertStatus.UNDETERMINED);
+ }
+ if (certStatus.getCertStatus() == CertStatus.UNDETERMINED)
+ {
+ throw new AnnotatedException("Certificate status could not be determined.");
+ }
+ }
+
+ protected static int prepareNextCertJ(
+ CertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (j)
+ //
+ DERInteger iap = null;
+ try
+ {
+ iap = DERInteger.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.INHIBIT_ANY_POLICY));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Inhibit any-policy extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.getValue().intValue();
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ {
+ return _inhibitAnyPolicy;
+ }
+ }
+ return inhibitAnyPolicy;
+ }
+
+ protected static void prepareNextCertK(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (k)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ if (!(bc.isCA()))
+ {
+ throw new CertPathValidatorException("Not a CA certificate");
+ }
+ }
+ else
+ {
+ throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+ }
+ }
+
+ protected static int prepareNextCertL(
+ CertPath certPath,
+ int index,
+ int maxPathLength)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (l)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ throw new ExtCertPathValidatorException("Max path length not greater than zero", null, certPath, index);
+ }
+
+ return maxPathLength - 1;
+ }
+ return maxPathLength;
+ }
+
+ protected static int prepareNextCertM(
+ CertPath certPath,
+ int index,
+ int maxPathLength)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+
+ //
+ // (m)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.intValue();
+
+ if (_plc < maxPathLength)
+ {
+ return _plc;
+ }
+ }
+ }
+ return maxPathLength;
+ }
+
+ protected static void prepareNextCertN(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+
+ //
+ // (n)
+ //
+ boolean[] _usage = cert.getKeyUsage();
+
+ if ((_usage != null) && !_usage[RFC3280CertPathUtilities.KEY_CERT_SIGN])
+ {
+ throw new ExtCertPathValidatorException(
+ "Issuer certificate keyusage extension is critical and does not permit key signing.", null,
+ certPath, index);
+ }
+ }
+
+ protected static void prepareNextCertO(
+ CertPath certPath,
+ int index,
+ Set criticalExtensions,
+ List pathCheckers)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (o)
+ //
+
+ Iterator tmpIter;
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+ }
+ }
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath,
+ index);
+ }
+ }
+
+ protected static int prepareNextCertH1(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (1)
+ //
+ if (explicitPolicy != 0)
+ {
+ return explicitPolicy - 1;
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static int prepareNextCertH2(
+ CertPath certPath,
+ int index,
+ int policyMapping)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (2)
+ //
+ if (policyMapping != 0)
+ {
+ return policyMapping - 1;
+ }
+ }
+ return policyMapping;
+ }
+
+ protected static int prepareNextCertH3(
+ CertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (3)
+ //
+ if (inhibitAnyPolicy != 0)
+ {
+ return inhibitAnyPolicy - 1;
+ }
+ }
+ return inhibitAnyPolicy;
+ }
+
+ protected static final String[] crlReasons = new String[]
+ {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ protected static int wrapupCertA(
+ int explicitPolicy,
+ X509Certificate cert)
+ {
+ //
+ // (a)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0))
+ {
+ explicitPolicy--;
+ }
+ return explicitPolicy;
+ }
+
+ protected static int wrapupCertB(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (b)
+ //
+ int tmpInt;
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
+ }
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ try
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
+ index);
+ }
+ if (tmpInt == 0)
+ {
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static void wrapupCertF(
+ CertPath certPath,
+ int index,
+ List pathCheckers,
+ Set criticalExtensions)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ Iterator tmpIter;
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException("Additional certificate path checker failed.", e, certPath,
+ index);
+ }
+ }
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath,
+ index);
+ }
+ }
+
+ protected static PKIXPolicyNode wrapupCertG(
+ CertPath certPath,
+ ExtendedPKIXParameters paramsPKIX,
+ Set userInitialPolicySet,
+ int index,
+ List[] policyNodes,
+ PKIXPolicyNode validPolicyTree,
+ Set acceptablePolicies)
+ throws CertPathValidatorException
+ {
+ int n = certPath.getCertificates().size();
+ //
+ // (g)
+ //
+ PKIXPolicyNode intersection;
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+ certPath, index);
+ }
+ intersection = null;
+ }
+ else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g)
+ // (ii)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ if (acceptablePolicies.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+ certPath, index);
+ }
+ else
+ {
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ _validPolicyNodeSet.add(_iter.next());
+ }
+ }
+ }
+ }
+
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!acceptablePolicies.contains(_validPolicy))
+ {
+ // validPolicyTree =
+ // removePolicyNode(validPolicyTree, policyNodes,
+ // _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree,
+ policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in
+ // RFC3280.
+ // However, as far as the validation result is concerned, both
+ // produce
+ // adequate result. The only difference is whether AnyPolicy is
+ // remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+ if (!RFC3280CertPathUtilities.ANY_POLICY.equals(_c_node.getValidPolicy()))
+ {
+ _validPolicyNodeSet.add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!userInitialPolicySet.contains(_validPolicy))
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes,
+ node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ return intersection;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java
new file mode 100644
index 000000000..cbbc098af
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java
@@ -0,0 +1,293 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+import org.spongycastle.jce.X509Principal;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+public class X509CRLEntryObject extends X509CRLEntry
+{
+ private TBSCertList.CRLEntry c;
+
+ private X500Name certificateIssuer;
+ private int hashValue;
+ private boolean isHashValueSet;
+
+ public X509CRLEntryObject(TBSCertList.CRLEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = null;
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+ * is <code>false</code> {@link #getCertificateIssuer()} will always
+ * return <code>null</code>, <code>previousCertificateIssuer</code> is
+ * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+ * has no certificate issuer CRL entry extension
+ * <code>previousCertificateIssuer</code> is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TBSCertList.CRLEntry object.
+ * @param isIndirect
+ * <code>true</code> if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CRLEntry.
+ */
+ public X509CRLEntryObject(
+ TBSCertList.CRLEntry c,
+ boolean isIndirect,
+ X500Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+ }
+
+ /**
+ * Will return true if any extensions are present and marked as critical as
+ * we currently don't handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ return extns != null && !extns.isEmpty();
+ }
+
+ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId());
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.getInstance(
+ X509ExtensionUtil.fromExtensionValue(ext)).getNames();
+ for (int i = 0; i < names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ return X500Name.getInstance(names[i].getName());
+ }
+ }
+ return null;
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ X509Principal getCertificateIssuer()
+ {
+ if (certificateIssuer == null)
+ {
+ return null;
+ }
+ try
+ {
+ return new X509Principal(certificateIssuer.getEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(e.toString());
+ }
+ }
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Cache the hashCode value - calculating it with the standard method.
+ * @return calculated hashCode.
+ */
+ public int hashCode()
+ {
+ if (!isHashValueSet)
+ {
+ hashValue = super.hashCode();
+ isHashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getUserCertificate().getValue();
+ }
+
+ public Date getRevocationDate()
+ {
+ return c.getRevocationDate().getDate();
+ }
+
+ public boolean hasExtensions()
+ {
+ return c.getExtensions() != null;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl);
+
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+ if (e.hasMoreElements())
+ {
+ buf.append(" crlEntryExtensions:").append(nl);
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(X509Extension.reasonCode))
+ {
+ buf.append(CRLReason.getInstance(DEREnumerated.getInstance(dIn.readObject()))).append(nl);
+ }
+ else if (oid.equals(X509Extension.certificateIssuer))
+ {
+ buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java
new file mode 100644
index 000000000..ce0de272b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java
@@ -0,0 +1,556 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLNumber;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+public class X509CRLObject
+ extends X509CRL
+{
+ private CertificateList c;
+ private String sigAlgName;
+ private byte[] sigAlgParams;
+ private boolean isIndirect;
+
+ static boolean isIndirectCRL(X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+ return idp != null
+ && IssuingDistributionPoint.getInstance(X509ExtensionUtil.fromExtensionValue(idp)).isIndirectCRL();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCRLException(
+ "Exception reading IssuingDistributionPoint", e);
+ }
+ }
+
+ public X509CRLObject(
+ CertificateList c)
+ throws CRLException
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = isIndirectCRL(this);
+ }
+ catch (Exception e)
+ {
+ throw new CRLException("CRL contents invalid: " + e);
+ }
+ }
+
+ /**
+ * Will return true if any extensions are present and marked
+ * as critical as we currently dont handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ if (extns == null)
+ {
+ return false;
+ }
+
+ extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+ return !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ if (this.getVersion() == 2)
+ {
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertList().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ verify(key, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+ {
+ throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+ }
+
+ Signature sig;
+
+ if (sigProvider != null)
+ {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+ else
+ {
+ sig = Signature.getInstance(getSigAlgName());
+ }
+
+ sig.initVerify(key);
+ sig.update(this.getTBSCertList());
+
+ if (!sig.verify(this.getSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public Principal getIssuerDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+ }
+
+ public Date getThisUpdate()
+ {
+ return c.getThisUpdate().getDate();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (c.getNextUpdate() != null)
+ {
+ return c.getNextUpdate().getDate();
+ }
+
+ return null;
+ }
+
+ private Set loadCRLEntries()
+ {
+ Set entrySet = new HashSet();
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+ X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ entrySet.add(crlEntry);
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return entrySet;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+ {
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+ if (serialNumber.equals(entry.getUserCertificate().getValue()))
+ {
+ return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getRevokedCertificates()
+ {
+ Set entrySet = loadCRLEntries();
+
+ if (!entrySet.isEmpty())
+ {
+ return Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public byte[] getTBSCertList()
+ throws CRLException
+ {
+ try
+ {
+ return c.getTBSCertList().getEncoded("DER");
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ public String getSigAlgName()
+ {
+ return sigAlgName;
+ }
+
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ {
+ byte[] tmp = new byte[sigAlgParams.length];
+
+ System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" Version: ").append(this.getVersion()).append(
+ nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN())
+ .append(nl);
+ buf.append(" This update: ").append(this.getThisUpdate())
+ .append(nl);
+ buf.append(" Next update: ").append(this.getNextUpdate())
+ .append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName())
+ .append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(
+ new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: ").append(nl);
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(
+ ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.cRLNumber))
+ {
+ buf.append(
+ new CRLNumber(DERInteger.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid.equals(Extension.deltaCRLIndicator))
+ {
+ buf.append(
+ "Base CRL: "
+ + new CRLNumber(DERInteger.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid
+ .equals(Extension.issuingDistributionPoint))
+ {
+ buf.append(
+ IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid
+ .equals(Extension.cRLDistributionPoints))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.freshestCRL))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(
+ ASN1Dump.dumpAsString(dIn.readObject()))
+ .append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ Set set = getRevokedCertificates();
+ if (set != null)
+ {
+ Iterator it = set.iterator();
+ while (it.hasNext())
+ {
+ buf.append(it.next());
+ buf.append(nl);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!cert.getType().equals("X.509"))
+ {
+ throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+ }
+
+ TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+
+ X500Name caName = c.getIssuer();
+
+ if (certs != null)
+ {
+ BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+ for (int i = 0; i < certs.length; i++)
+ {
+ if (isIndirect && certs[i].hasExtensions())
+ {
+ Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+
+ if (certs[i].getUserCertificate().getValue().equals(serial))
+ {
+ X500Name issuer;
+
+ try
+ {
+ issuer = org.spongycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new RuntimeException("Cannot process certificate");
+ }
+
+ if (!caName.equals(issuer))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java
new file mode 100644
index 000000000..74b9c6115
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java
@@ -0,0 +1,858 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.misc.NetscapeRevocationURL;
+import org.spongycastle.asn1.misc.VerisignCzagExtension;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.encoders.Hex;
+
+public class X509CertificateObject
+ extends X509Certificate
+ implements PKCS12BagAttributeCarrier
+{
+ private org.spongycastle.asn1.x509.Certificate c;
+ private BasicConstraints basicConstraints;
+ private boolean[] keyUsage;
+ private boolean hashValueSet;
+ private int hashValue;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ public X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate c)
+ throws CertificateParsingException
+ {
+ this.c = c;
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.19");
+
+ if (bytes != null)
+ {
+ basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.15");
+ if (bytes != null)
+ {
+ DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+ bytes = bits.getBytes();
+ int length = (bytes.length * 8) - bits.getPadBits();
+
+ keyUsage = new boolean[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+ keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility
+ {
+ throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+ }
+
+ if (date.getTime() < this.getNotBefore().getTime())
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getSerialNumber().getValue();
+ }
+
+ public Principal getIssuerDN()
+ {
+ try
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public Principal getSubjectDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+ }
+
+ public Date getNotBefore()
+ {
+ return c.getStartDate().getDate();
+ }
+
+ public Date getNotAfter()
+ {
+ return c.getEndDate().getDate();
+ }
+
+ public byte[] getTBSCertificate()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ /**
+ * return a more "meaningful" representation for the signature algorithm used in
+ * the certficate.
+ */
+ public String getSigAlgName()
+ {
+ Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ if (prov != null)
+ {
+ String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ Provider[] provs = Security.getProviders();
+
+ //
+ // search every provider looking for a real algorithm
+ //
+ for (int i = 0; i != provs.length; i++)
+ {
+ String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ return this.getSigAlgOID();
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getSigAlgParams()
+ {
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ try
+ {
+ return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getIssuerUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getSubjectUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ return keyUsage;
+ }
+
+ public List getExtendedKeyUsage()
+ throws CertificateParsingException
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.37");
+
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension");
+ }
+ }
+
+ return null;
+ }
+
+ public int getBasicConstraints()
+ {
+ if (basicConstraints != null)
+ {
+ if (basicConstraints.isCA())
+ {
+ if (basicConstraints.getPathLenConstraint() == null)
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return basicConstraints.getPathLenConstraint().intValue();
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ public Collection getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+ }
+
+ public Collection getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getExtensionBytes(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+ if (ext != null)
+ {
+ return ext.getExtnValue().getOctets();
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (!ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ if (this.getVersion() == 3)
+ {
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ String oidId = oid.getId();
+
+ if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
+ || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
+ || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
+ || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
+ || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
+ || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
+ || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
+ {
+ continue;
+ }
+
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ try
+ {
+ return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ return null; // should never happen...
+ }
+ }
+
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof Certificate))
+ {
+ return false;
+ }
+
+ Certificate other = (Certificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public synchronized int hashCode()
+ {
+ if (!hashValueSet)
+ {
+ hashValue = calculateHashCode();
+ hashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ private int calculateHashCode()
+ {
+ try
+ {
+ int hashCode = 0;
+ byte[] certData = this.getEncoded();
+ for (int i = 1; i < certData.length; i++)
+ {
+ hashCode += certData[i] * i;
+ }
+ return hashCode;
+ }
+ catch (CertificateEncodingException e)
+ {
+ return 0;
+ }
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" [0] Version: ").append(this.getVersion()).append(nl);
+ buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl);
+ buf.append(" Start Date: ").append(this.getNotBefore()).append(nl);
+ buf.append(" Final Date: ").append(this.getNotAfter()).append(nl);
+ buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl);
+ buf.append(" Public Key: ").append(this.getPublicKey()).append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: \n");
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.basicConstraints))
+ {
+ buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.keyUsage))
+ {
+ buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+ {
+ buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+ {
+ buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+ {
+ buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ //buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public final void verify(
+ PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature;
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ try
+ {
+ signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ signature = Signature.getInstance(sigName);
+ }
+
+ checkSignature(key, signature);
+ }
+
+ public final void verify(
+ PublicKey key,
+ String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+ Signature signature = Signature.getInstance(sigName, sigProvider);
+
+ checkSignature(key, signature);
+ }
+
+ private void checkSignature(
+ PublicKey key,
+ Signature signature)
+ throws CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException
+ {
+ if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+ // TODO This should go after the initVerify?
+ X509SignatureUtil.setSignatureParameters(signature, params);
+
+ signature.initVerify(key);
+
+ signature.update(this.getTBSCertificate());
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new SignatureException("certificate does not verify with supplied key");
+ }
+ }
+
+ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+ {
+ return false;
+ }
+
+ if (id1.getParameters() == null)
+ {
+ if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (id2.getParameters() == null)
+ {
+ if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return id1.getParameters().equals(id2.getParameters());
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return null;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ list.add(Integers.valueOf(genName.getTagNo()));
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getEncoded());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+ list.add(addrBytes);
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(list);
+ }
+ if (temp.size() == 0)
+ {
+ return null;
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java
new file mode 100644
index 000000000..0711e29c8
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java
@@ -0,0 +1,44 @@
+package org.spongycastle.jce.spec;
+
+/**
+ * This class specifies a parameter spec for RSA PSS encoding scheme,
+ * as defined in the PKCS#1 v2.1.
+ *
+ * @see java.security.spec.AlgorithmParameterSpec
+ * @see java.security.Signature
+ */
+public class PSSParameterSpec
+ extends Object
+ implements java.security.spec.AlgorithmParameterSpec
+{
+ private int saltLen;
+
+ /**
+ * Creates a new PSSParameterSpec given the salt length as defined
+ * in PKCS#1.
+ *
+ * @param saltLen - the length of salt in bits to be used in PKCS#1
+ * PSS encoding.
+ * @throws IllegalArgumentException - if saltLen is less than 0.
+ */
+ public PSSParameterSpec(int saltLen)
+ {
+ if (saltLen < 0)
+ {
+ throw new IllegalArgumentException("Salt length must be >= 0");
+ }
+
+ this.saltLen = saltLen;
+ }
+
+ /**
+ * Returns the salt length in bits.
+ *
+ * @returns the salt length.
+ */
+ public int getSaltLength()
+ {
+ return saltLen;
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/BasicOCSPResp.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/BasicOCSPResp.java
new file mode 100644
index 000000000..1e64236ff
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/BasicOCSPResp.java
@@ -0,0 +1,366 @@
+package org.spongycastle.ocsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreParameters;
+import java.security.cert.CertificateException;
+import org.spongycastle.jce.cert.CertificateFactory;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import java.security.cert.X509Certificate;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.ocsp.BasicOCSPResponse;
+import org.spongycastle.asn1.ocsp.ResponseData;
+import org.spongycastle.asn1.ocsp.SingleResponse;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+
+/**
+ * <pre>
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ * </pre>
+ *
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+public class BasicOCSPResp
+ implements java.security.cert.X509Extension
+{
+ BasicOCSPResponse resp;
+ ResponseData data;
+ X509Certificate[] chain = null;
+
+ public BasicOCSPResp(
+ BasicOCSPResponse resp)
+ {
+ this.resp = resp;
+ this.data = resp.getTbsResponseData();
+ }
+
+ /**
+ * Return the DER encoding of the tbsResponseData field.
+ * @return DER encoding of tbsResponseData
+ * @throws OCSPException in the event of an encoding error.
+ */
+ public byte[] getTBSResponseData()
+ throws OCSPException
+ {
+ try
+ {
+ return resp.getTbsResponseData().getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new OCSPException("problem encoding tbsResponseData", e);
+ }
+ }
+
+ public int getVersion()
+ {
+ return data.getVersion().getValue().intValue() + 1;
+ }
+
+ public RespID getResponderId()
+ {
+ return new RespID(data.getResponderID());
+ }
+
+ public Date getProducedAt()
+ {
+ try
+ {
+ return data.getProducedAt().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IllegalStateException("ParseException:" + e.getMessage());
+ }
+ }
+
+ public SingleResp[] getResponses()
+ {
+ ASN1Sequence s = data.getResponses();
+ SingleResp[] rs = new SingleResp[s.size()];
+
+ for (int i = 0; i != rs.length; i++)
+ {
+ rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i)));
+ }
+
+ return rs;
+ }
+
+ public X509Extensions getResponseExtensions()
+ {
+ return X509Extensions.getInstance(data.getResponseExtensions());
+ }
+
+ /**
+ * RFC 2650 doesn't specify any critical extensions so we return true
+ * if any are encountered.
+ *
+ * @return true if any critical extensions are present.
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+ if (extns != null && !extns.isEmpty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = this.getResponseExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+ }
+
+ return set;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ X509Extensions exts = this.getResponseExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String getSignatureAlgName()
+ {
+ return OCSPUtil.getAlgorithmName(resp.getSignatureAlgorithm().getObjectId());
+ }
+
+ public String getSignatureAlgOID()
+ {
+ return resp.getSignatureAlgorithm().getObjectId().getId();
+ }
+
+ /**
+ * @deprecated RespData class is no longer required as all functionality is
+ * available on this class.
+ * @return the RespData object
+ */
+ public RespData getResponseData()
+ {
+ return new RespData(resp.getTbsResponseData());
+ }
+
+ public byte[] getSignature()
+ {
+ return resp.getSignature().getBytes();
+ }
+
+ private List getCertList(
+ String provider)
+ throws OCSPException, NoSuchProviderException
+ {
+ List certs = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+ CertificateFactory cf;
+
+ try
+ {
+ cf = OCSPUtil.createX509CertificateFactory(provider);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OCSPException("can't get certificate factory.", ex);
+ }
+
+ //
+ // load the certificates and revocation lists if we have any
+ //
+ ASN1Sequence s = resp.getCerts();
+
+ if (s != null)
+ {
+ Enumeration e = s.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ certs.add(cf.generateCertificate(
+ new ByteArrayInputStream(bOut.toByteArray())));
+ }
+ catch (IOException ex)
+ {
+ throw new OCSPException(
+ "can't re-encode certificate!", ex);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OCSPException(
+ "can't re-encode certificate!", ex);
+ }
+
+ bOut.reset();
+ }
+ }
+
+ return certs;
+ }
+
+ public X509Certificate[] getCerts(
+ String provider)
+ throws OCSPException, NoSuchProviderException
+ {
+ List certs = getCertList(provider);
+
+ return (X509Certificate[])certs.toArray(new X509Certificate[certs.size()]);
+ }
+
+ /**
+ * Return the certificates, if any associated with the response.
+ * @param type type of CertStore to create
+ * @param provider provider to use
+ * @return a CertStore, possibly empty
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ * @throws OCSPException
+ */
+ public CertStore getCertificates(
+ String type,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException, OCSPException
+ {
+ try
+ {
+ CertStoreParameters params = new CollectionCertStoreParameters(this.getCertList(provider));
+ return OCSPUtil.createCertStoreInstance(type, params, provider);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new OCSPException("can't setup the CertStore", e);
+ }
+ }
+
+ /**
+ * verify the signature against the tbsResponseData object we contain.
+ */
+ public boolean verify(
+ PublicKey key,
+ String sigProvider)
+ throws OCSPException, NoSuchProviderException
+ {
+ try
+ {
+ Signature signature = OCSPUtil.createSignatureInstance(this.getSignatureAlgName(), sigProvider);
+
+ signature.initVerify(key);
+
+ signature.update(resp.getTbsResponseData().getEncoded(ASN1Encoding.DER));
+
+ return signature.verify(this.getSignature());
+ }
+ catch (NoSuchProviderException e)
+ {
+ // TODO Why this special case?
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing sig: " + e, e);
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return resp.getEncoded();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof BasicOCSPResp))
+ {
+ return false;
+ }
+
+ BasicOCSPResp r = (BasicOCSPResp)o;
+
+ return resp.equals(r.resp);
+ }
+
+ public int hashCode()
+ {
+ return resp.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPReq.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPReq.java
new file mode 100644
index 000000000..7f4a091f0
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPReq.java
@@ -0,0 +1,415 @@
+package org.spongycastle.ocsp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ocsp.OCSPRequest;
+import org.spongycastle.asn1.ocsp.Request;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreParameters;
+import org.spongycastle.jce.cert.CertificateFactory;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+
+/**
+ * <pre>
+ * OCSPRequest ::= SEQUENCE {
+ * tbsRequest TBSRequest,
+ * optionalSignature [0] EXPLICIT Signature OPTIONAL }
+ *
+ * TBSRequest ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ * requestList SEQUENCE OF Request,
+ * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+ *
+ * Signature ::= SEQUENCE {
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+ *
+ * Version ::= INTEGER { v1(0) }
+ *
+ * Request ::= SEQUENCE {
+ * reqCert CertID,
+ * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+ *
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ * serialNumber CertificateSerialNumber }
+ * </pre>
+ */
+public class OCSPReq
+ implements java.security.cert.X509Extension
+{
+ private OCSPRequest req;
+
+ public OCSPReq(
+ OCSPRequest req)
+ {
+ this.req = req;
+ }
+
+ public OCSPReq(
+ byte[] req)
+ throws IOException
+ {
+ this(new ASN1InputStream(req));
+ }
+
+ public OCSPReq(
+ InputStream in)
+ throws IOException
+ {
+ this(new ASN1InputStream(in));
+ }
+
+ private OCSPReq(
+ ASN1InputStream aIn)
+ throws IOException
+ {
+ try
+ {
+ this.req = OCSPRequest.getInstance(aIn.readObject());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("malformed request: " + e.getMessage());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("malformed request: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Return the DER encoding of the tbsRequest field.
+ * @return DER encoding of tbsRequest
+ * @throws OCSPException in the event of an encoding error.
+ */
+ public byte[] getTBSRequest()
+ throws OCSPException
+ {
+ try
+ {
+ return req.getTbsRequest().getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new OCSPException("problem encoding tbsRequest", e);
+ }
+ }
+
+ public int getVersion()
+ {
+ return req.getTbsRequest().getVersion().getValue().intValue() + 1;
+ }
+
+ public GeneralName getRequestorName()
+ {
+ return GeneralName.getInstance(req.getTbsRequest().getRequestorName());
+ }
+
+ public Req[] getRequestList()
+ {
+ ASN1Sequence seq = req.getTbsRequest().getRequestList();
+ Req[] requests = new Req[seq.size()];
+
+ for (int i = 0; i != requests.length; i++)
+ {
+ requests[i] = new Req(Request.getInstance(seq.getObjectAt(i)));
+ }
+
+ return requests;
+ }
+
+ public X509Extensions getRequestExtensions()
+ {
+ return X509Extensions.getInstance(req.getTbsRequest().getRequestExtensions());
+ }
+
+ /**
+ * return the object identifier representing the signature algorithm
+ */
+ public String getSignatureAlgOID()
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ return req.getOptionalSignature().getSignatureAlgorithm().getObjectId().getId();
+ }
+
+ public byte[] getSignature()
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ return req.getOptionalSignature().getSignature().getBytes();
+ }
+
+ private List getCertList(
+ String provider)
+ throws OCSPException, NoSuchProviderException
+ {
+ List certs = new ArrayList();
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+ CertificateFactory cf;
+
+ try
+ {
+ cf = OCSPUtil.createX509CertificateFactory(provider);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OCSPException("can't get certificate factory.", ex);
+ }
+
+ //
+ // load the certificates if we have any
+ //
+ ASN1Sequence s = req.getOptionalSignature().getCerts();
+
+ if (s != null)
+ {
+ Enumeration e = s.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ certs.add(cf.generateCertificate(
+ new ByteArrayInputStream(bOut.toByteArray())));
+ }
+ catch (IOException ex)
+ {
+ throw new OCSPException(
+ "can't re-encode certificate!", ex);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OCSPException(
+ "can't re-encode certificate!", ex);
+ }
+
+ bOut.reset();
+ }
+ }
+
+ return certs;
+ }
+
+ public X509Certificate[] getCerts(
+ String provider)
+ throws OCSPException, NoSuchProviderException
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ List certs = this.getCertList(provider);
+
+ return (X509Certificate[])certs.toArray(new X509Certificate[certs.size()]);
+ }
+
+ /**
+ * If the request is signed return a possibly empty CertStore containing the certificates in the
+ * request. If the request is not signed the method returns null.
+ *
+ * @param type type of CertStore to return
+ * @param provider provider to use
+ * @return null if not signed, a CertStore otherwise
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ * @throws OCSPException
+ */
+ public CertStore getCertificates(
+ String type,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException, OCSPException
+ {
+ if (!this.isSigned())
+ {
+ return null;
+ }
+
+ try
+ {
+ CertStoreParameters params = new CollectionCertStoreParameters(this.getCertList(provider));
+ return OCSPUtil.createCertStoreInstance(type, params, provider);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new OCSPException("can't setup the CertStore", e);
+ }
+ }
+
+ /**
+ * Return whether or not this request is signed.
+ *
+ * @return true if signed false otherwise.
+ */
+ public boolean isSigned()
+ {
+ return req.getOptionalSignature() != null;
+ }
+
+ /**
+ * verify the signature against the TBSRequest object we contain.
+ */
+ public boolean verify(
+ PublicKey key,
+ String sigProvider)
+ throws OCSPException, NoSuchProviderException
+ {
+ if (!this.isSigned())
+ {
+ throw new OCSPException("attempt to verify signature on unsigned object");
+ }
+
+ try
+ {
+ Signature signature = OCSPUtil.createSignatureInstance(this.getSignatureAlgOID(), sigProvider);
+
+ signature.initVerify(key);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(req.getTbsRequest());
+
+ signature.update(bOut.toByteArray());
+
+ return signature.verify(this.getSignature());
+ }
+ catch (NoSuchProviderException e)
+ {
+ // TODO Why this special case?
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing sig: " + e, e);
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(req);
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * RFC 2650 doesn't specify any critical extensions so we return true
+ * if any are encountered.
+ *
+ * @return true if any critical extensions are present.
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+ if (extns != null && !extns.isEmpty())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = this.getRequestExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+ }
+
+ return set;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ X509Extensions exts = this.getRequestExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPReqGenerator.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPReqGenerator.java
new file mode 100644
index 000000000..755751fb6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPReqGenerator.java
@@ -0,0 +1,292 @@
+package org.spongycastle.ocsp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.ocsp.OCSPRequest;
+import org.spongycastle.asn1.ocsp.Request;
+import org.spongycastle.asn1.ocsp.Signature;
+import org.spongycastle.asn1.ocsp.TBSRequest;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.X509CertificateStructure;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.X509Principal;
+
+/**
+ * @deprecated use classes in org.spongycastle.cert.ocsp.
+ */
+public class OCSPReqGenerator
+{
+ private List list = new ArrayList();
+ private GeneralName requestorName = null;
+ private X509Extensions requestExtensions = null;
+
+ private class RequestObject
+ {
+ CertificateID certId;
+ X509Extensions extensions;
+
+ public RequestObject(
+ CertificateID certId,
+ X509Extensions extensions)
+ {
+ this.certId = certId;
+ this.extensions = extensions;
+ }
+
+ public Request toRequest()
+ throws Exception
+ {
+ return new Request(certId.toASN1Object(), Extensions.getInstance(extensions));
+ }
+ }
+
+ /**
+ * Add a request for the given CertificateID.
+ *
+ * @param certId certificate ID of interest
+ */
+ public void addRequest(
+ CertificateID certId)
+ {
+ list.add(new RequestObject(certId, null));
+ }
+
+ /**
+ * Add a request with extensions
+ *
+ * @param certId certificate ID of interest
+ * @param singleRequestExtensions the extensions to attach to the request
+ */
+ public void addRequest(
+ CertificateID certId,
+ X509Extensions singleRequestExtensions)
+ {
+ list.add(new RequestObject(certId, singleRequestExtensions));
+ }
+
+ /**
+ * Set the requestor name to the passed in X500Principal
+ *
+ * @param requestorName a X500Principal representing the requestor name.
+ */
+ public void setRequestorName(
+ X509Principal requestorName)
+ {
+ try
+ {
+ this.requestorName = new GeneralName(GeneralName.directoryName, new X509Principal(requestorName.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("cannot encode principal: " + e);
+ }
+ }
+
+ public void setRequestorName(
+ GeneralName requestorName)
+ {
+ this.requestorName = requestorName;
+ }
+
+ public void setRequestExtensions(
+ X509Extensions requestExtensions)
+ {
+ this.requestExtensions = requestExtensions;
+ }
+
+ private OCSPReq generateRequest(
+ DERObjectIdentifier signingAlgorithm,
+ PrivateKey key,
+ X509Certificate[] chain,
+ String provider,
+ SecureRandom random)
+ throws OCSPException, NoSuchProviderException
+ {
+ Iterator it = list.iterator();
+
+ ASN1EncodableVector requests = new ASN1EncodableVector();
+
+ while (it.hasNext())
+ {
+ try
+ {
+ requests.add(((RequestObject)it.next()).toRequest());
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception creating Request", e);
+ }
+ }
+
+ TBSRequest tbsReq = new TBSRequest(requestorName, new DERSequence(requests), requestExtensions);
+
+ java.security.Signature sig = null;
+ Signature signature = null;
+
+ if (signingAlgorithm != null)
+ {
+ if (requestorName == null)
+ {
+ throw new OCSPException("requestorName must be specified if request is signed.");
+ }
+
+ try
+ {
+ sig = OCSPUtil.createSignatureInstance(signingAlgorithm.getId(), provider);
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ // TODO Why this special case?
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new OCSPException("exception creating signature: " + e, e);
+ }
+
+ DERBitString bitSig = null;
+
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(tbsReq);
+
+ sig.update(bOut.toByteArray());
+
+ bitSig = new DERBitString(sig.sign());
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("exception processing TBSRequest: " + e, e);
+ }
+
+ AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(signingAlgorithm, new DERNull());
+
+ if (chain != null && chain.length > 0)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ try
+ {
+ for (int i = 0; i != chain.length; i++)
+ {
+ v.add(new X509CertificateStructure(
+ (ASN1Sequence)ASN1Primitive.fromByteArray(chain[i].getEncoded())));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new OCSPException("error processing certs", e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OCSPException("error encoding certs", e);
+ }
+
+ signature = new Signature(sigAlgId, bitSig, new DERSequence(v));
+ }
+ else
+ {
+ signature = new Signature(sigAlgId, bitSig);
+ }
+ }
+
+ return new OCSPReq(new OCSPRequest(tbsReq, signature));
+ }
+
+ /**
+ * Generate an unsigned request
+ *
+ * @return the OCSPReq
+ * @throws OCSPException
+ */
+ public OCSPReq generate()
+ throws OCSPException
+ {
+ try
+ {
+ return generateRequest(null, null, null, null, null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ //
+ // this shouldn't happen but...
+ //
+ throw new OCSPException("no provider! - " + e, e);
+ }
+ }
+
+ public OCSPReq generate(
+ String signingAlgorithm,
+ PrivateKey key,
+ X509Certificate[] chain,
+ String provider)
+ throws OCSPException, NoSuchProviderException, IllegalArgumentException
+ {
+ return generate(signingAlgorithm, key, chain, provider, null);
+ }
+
+ public OCSPReq generate(
+ String signingAlgorithm,
+ PrivateKey key,
+ X509Certificate[] chain,
+ String provider,
+ SecureRandom random)
+ throws OCSPException, NoSuchProviderException, IllegalArgumentException
+ {
+ if (signingAlgorithm == null)
+ {
+ throw new IllegalArgumentException("no signing algorithm specified");
+ }
+
+ try
+ {
+ DERObjectIdentifier oid = OCSPUtil.getAlgorithmOID(signingAlgorithm);
+
+ return generateRequest(oid, key, chain, provider, random);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IllegalArgumentException("unknown signing algorithm specified: " + signingAlgorithm);
+ }
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return OCSPUtil.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPUtil.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPUtil.java
new file mode 100644
index 000000000..ddcadda32
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/OCSPUtil.java
@@ -0,0 +1,198 @@
+package org.spongycastle.ocsp;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.util.Strings;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreParameters;
+import java.security.cert.CertificateException;
+import org.spongycastle.jce.cert.CertificateFactory;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+class OCSPUtil
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable oids = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+
+ oids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2WITHRSA");
+ oids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, "RIPEMD160WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, "RIPEMD128WITHRSA");
+ oids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, "RIPEMD256WITHRSA");
+ oids.put(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ }
+
+ static DERObjectIdentifier getAlgorithmOID(
+ String algorithmName)
+ {
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (algorithms.containsKey(algorithmName))
+ {
+ return (DERObjectIdentifier)algorithms.get(algorithmName);
+ }
+
+ return new DERObjectIdentifier(algorithmName);
+ }
+
+ static String getAlgorithmName(
+ DERObjectIdentifier oid)
+ {
+ if (oids.containsKey(oid))
+ {
+ return (String)oids.get(oid);
+ }
+
+ return oid.getId();
+ }
+
+ static AlgorithmIdentifier getSigAlgID(
+ DERObjectIdentifier sigOid)
+ {
+ if (noParams.contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+ else
+ {
+ return new AlgorithmIdentifier(sigOid, new DERNull());
+ }
+ }
+
+ static Iterator getAlgNames()
+ {
+ Enumeration e = algorithms.keys();
+ List l = new ArrayList();
+
+ while (e.hasMoreElements())
+ {
+ l.add(e.nextElement());
+ }
+
+ return l.iterator();
+ }
+
+ static CertStore createCertStoreInstance(String type, CertStoreParameters params, String provider)
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return CertStore.getInstance(type, params);
+ }
+
+ return CertStore.getInstance(type, params, provider);
+ }
+
+ static MessageDigest createDigestInstance(String digestName, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return MessageDigest.getInstance(digestName);
+ }
+
+ return MessageDigest.getInstance(digestName, provider);
+ }
+
+ static Signature createSignatureInstance(String sigName, String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return Signature.getInstance(sigName);
+ }
+
+ return Signature.getInstance(sigName, provider);
+ }
+
+ static CertificateFactory createX509CertificateFactory(String provider)
+ throws CertificateException, NoSuchProviderException
+ {
+ if (provider == null)
+ {
+ return CertificateFactory.getInstance("X.509");
+ }
+
+ return CertificateFactory.getInstance("X.509", provider);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/RespID.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/RespID.java
new file mode 100644
index 000000000..8a491d046
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/ocsp/RespID.java
@@ -0,0 +1,80 @@
+package org.spongycastle.ocsp;
+
+import java.security.MessageDigest;
+import java.security.PublicKey;
+
+import org.spongycastle.jce.X509Principal;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.ocsp.ResponderID;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * Carrier for a ResponderID.
+ */
+public class RespID
+{
+ ResponderID id;
+
+ public RespID(
+ ResponderID id)
+ {
+ this.id = id;
+ }
+
+ public RespID(
+ X509Principal name)
+ {
+ this.id = new ResponderID(X500Name.getInstance(name.getEncoded()));
+ }
+
+ public RespID(
+ PublicKey key)
+ throws OCSPException
+ {
+ try
+ {
+ // TODO Allow specification of a particular provider
+ MessageDigest digest = OCSPUtil.createDigestInstance("SHA1", null);
+
+ ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ digest.update(info.getPublicKeyData().getBytes());
+
+ ASN1OctetString keyHash = new DEROctetString(digest.digest());
+
+ this.id = new ResponderID(keyHash);
+ }
+ catch (Exception e)
+ {
+ throw new OCSPException("problem creating ID: " + e, e);
+ }
+ }
+
+ public ResponderID toASN1Object()
+ {
+ return id;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof RespID))
+ {
+ return false;
+ }
+
+ RespID obj = (RespID)o;
+
+ return id.equals(obj.id);
+ }
+
+ public int hashCode()
+ {
+ return id.hashCode();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateHolder.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateHolder.java
new file mode 100644
index 000000000..5b161b4de
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateHolder.java
@@ -0,0 +1,406 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.Holder;
+import org.spongycastle.asn1.x509.IssuerSerial;
+import org.spongycastle.asn1.x509.ObjectDigestInfo;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+
+/**
+ * The Holder object.
+ *
+ * <pre>
+ * Holder ::= SEQUENCE {
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * -- the issuer and serial number of
+ * -- the holder's Public Key Certificate
+ * entityName [1] GeneralNames OPTIONAL,
+ * -- the name of the claimant or role
+ * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ * -- used to directly authenticate the holder,
+ * -- for example, an executable
+ * }
+ * </pre>
+ * @deprecated use org.spongycastle.cert.AttributeCertificateHolder
+ */
+public class AttributeCertificateHolder
+ implements CertSelector, Selector
+{
+ final Holder holder;
+
+ AttributeCertificateHolder(ASN1Sequence seq)
+ {
+ holder = Holder.getInstance(seq);
+ }
+
+ public AttributeCertificateHolder(X509Principal issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new org.spongycastle.asn1.x509.Holder(new IssuerSerial(
+ new GeneralNames(new GeneralName(issuerName)),
+ new ASN1Integer(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ X509Principal name;
+
+ try
+ {
+ name = PrincipalUtil.getIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+
+ holder = new Holder(new IssuerSerial(generateGeneralNames(name),
+ new ASN1Integer(cert.getSerialNumber())));
+ }
+
+ public AttributeCertificateHolder(X509Principal principal)
+ {
+ holder = new Holder(generateGeneralNames(principal));
+ }
+
+ /**
+ * Constructs a holder for v2 attribute certificates with a hash value for
+ * some type of object.
+ * <p>
+ * <code>digestedObjectType</code> can be one of the following:
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ * <p>
+ * This cannot be used if a v1 attribute certificate is used.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param otherObjectTypeID The object type ID if
+ * <code>digestedObjectType</code> is
+ * <code>otherObjectDigest</code>.
+ * @param objectDigest The hash value.
+ */
+ public AttributeCertificateHolder(int digestedObjectType,
+ String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)
+ {
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType,
+ new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(digestAlgorithm), Arrays
+ .clone(objectDigest)));
+ }
+
+ /**
+ * Returns the digest object type if an object digest info is used.
+ * <p>
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ *
+ * @return The digest object type or -1 if no object digest info is set.
+ */
+ public int getDigestedObjectType()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestedObjectType()
+ .getValue().intValue();
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the other object type ID if an object digest info is used.
+ *
+ * @return The other object type ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getDigestAlgorithm()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId()
+ .getId();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or <code>null</code> if no object digest info is set.
+ */
+ public byte[] getObjectDigest()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getObjectDigest().getBytes();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the digest algorithm ID if an object digest info is used.
+ *
+ * @return The digest algorithm ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getOtherObjectTypeID()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
+ }
+ return null;
+ }
+
+ private GeneralNames generateGeneralNames(X509Principal principal)
+ {
+ return new GeneralNames(new GeneralName(principal));
+ }
+
+ private boolean matchesDN(X509Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
+ .getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private Object[] getNames(GeneralName[] names)
+ {
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X509Principal(
+ ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ private Principal[] getPrincipals(GeneralNames names)
+ {
+ Object[] p = this.getNames(names.getNames());
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate holder
+ * entity names field.
+ *
+ * @return an array of Principal objects (usually X509Principal), null if no
+ * entity names field is set.
+ */
+ public Principal[] getEntityNames()
+ {
+ if (holder.getEntityName() != null)
+ {
+ return getPrincipals(holder.getEntityName());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the principals associated with the issuer attached to this holder
+ *
+ * @return an array of principals, null if no BaseCertificateID is set.
+ */
+ public Principal[] getIssuer()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return getPrincipals(holder.getBaseCertificateID().getIssuer());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the serial number associated with the issuer attached to this
+ * holder.
+ *
+ * @return the certificate serial number, null if no BaseCertificateID is
+ * set.
+ */
+ public BigInteger getSerialNumber()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue();
+ }
+
+ return null;
+ }
+
+ public Object clone()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)holder
+ .toASN1Object());
+ }
+
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
+ }
+
+ if (holder.getEntityName() != null)
+ {
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert),
+ holder.getEntityName()))
+ {
+ return true;
+ }
+ }
+ if (holder.getObjectDigestInfo() != null)
+ {
+ MessageDigest md = null;
+ try
+ {
+ md = MessageDigest.getInstance(getDigestAlgorithm(), "SC");
+
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ switch (getDigestedObjectType())
+ {
+ case ObjectDigestInfo.publicKey:
+ // TODO: DSA Dss-parms
+ md.update(cert.getPublicKey().getEncoded());
+ break;
+ case ObjectDigestInfo.publicKeyCert:
+ md.update(cert.getEncoded());
+ break;
+ }
+ if (!Arrays.areEqual(md.digest(), getObjectDigest()))
+ {
+ return false;
+ }
+ }
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+ return this.holder.equals(other.holder);
+ }
+
+ public int hashCode()
+ {
+ return this.holder.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateIssuer.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateIssuer.java
new file mode 100644
index 000000000..44512802c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateIssuer.java
@@ -0,0 +1,211 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.x509.AttCertIssuer;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.V2Form;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.util.Selector;
+
+/**
+ * Carrying class for an attribute certificate issuer.
+ */
+public class AttributeCertificateIssuer
+ implements CertSelector, Selector
+{
+ final ASN1Encodable form;
+
+ /**
+ * @param issuer
+ */
+ AttributeCertificateIssuer(
+ AttCertIssuer issuer)
+ {
+ form = issuer.getIssuer();
+ }
+
+ public AttributeCertificateIssuer(
+ X509Principal principal)
+ {
+ form = new V2Form(new GeneralNames(new GeneralName(principal)));
+ }
+
+ private Object[] getNames()
+ {
+ GeneralNames name;
+
+ if (form instanceof V2Form)
+ {
+ name = ((V2Form)form).getIssuerName();
+ }
+ else
+ {
+ name = (GeneralNames)form;
+ }
+
+ GeneralName[] names = name.getNames();
+
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X509Principal(((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate issuer object.
+ *
+ * @return an array of Principal objects (usually X509Principal)
+ */
+ public Principal[] getPrincipals()
+ {
+ Object[] p = this.getNames();
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ private boolean matchesDN(X509Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive().getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.cert.CertSelector#clone()
+ */
+ public Object clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.cert.CertSelector#match(java.security.cert.Certificate)
+ */
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (form instanceof V2Form)
+ {
+ V2Form issuer = (V2Form)form;
+ if (issuer.getBaseCertificateID() != null)
+ {
+ return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), issuer.getBaseCertificateID().getIssuer());
+ }
+
+ GeneralNames name = issuer.getIssuerName();
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), name))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ GeneralNames name = (GeneralNames)form;
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), name))
+ {
+ return true;
+ }
+ }
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateIssuer))
+ {
+ return false;
+ }
+
+ AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+ return this.form.equals(other.form);
+ }
+
+ public int hashCode()
+ {
+ return this.form.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java
new file mode 100644
index 000000000..55d80de90
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java
@@ -0,0 +1,210 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import org.spongycastle.jce.cert.PKIXBuilderParameters;
+import org.spongycastle.jce.cert.PKIXParameters;
+import org.spongycastle.jce.cert.TrustAnchor;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class contains extended parameters for PKIX certification path builders.
+ *
+ * @see java.security.cert.PKIXBuilderParameters
+ * @see org.spongycastle.jce.provider.PKIXCertPathBuilderSpi
+ */
+public class ExtendedPKIXBuilderParameters extends ExtendedPKIXParameters
+{
+
+ private int maxPathLength = 5;
+
+ private Set excludedCerts = Collections.EMPTY_SET;
+
+ /**
+ * Excluded certificates are not used for building a certification path.
+ * <p>
+ * The returned set is immutable.
+ *
+ * @return Returns the excluded certificates.
+ */
+ public Set getExcludedCerts()
+ {
+ return Collections.unmodifiableSet(excludedCerts);
+ }
+
+ /**
+ * Sets the excluded certificates which are not used for building a
+ * certification path. If the <code>Set</code> is <code>null</code> an
+ * empty set is assumed.
+ * <p>
+ * The given set is cloned to protect it against subsequent modifications.
+ *
+ * @param excludedCerts The excluded certificates to set.
+ */
+ public void setExcludedCerts(Set excludedCerts)
+ {
+ if (excludedCerts == null)
+ {
+ excludedCerts = Collections.EMPTY_SET;
+ }
+ else
+ {
+ this.excludedCerts = new HashSet(excludedCerts);
+ }
+ }
+
+ /**
+ * Creates an instance of <code>PKIXBuilderParameters</code> with the
+ * specified <code>Set</code> of most-trusted CAs. Each element of the set
+ * is a {@link TrustAnchor TrustAnchor}.
+ *
+ * <p>
+ * Note that the <code>Set</code> is copied to protect against subsequent
+ * modifications.
+ *
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+ * @param targetConstraints a <code>Selector</code> specifying the
+ * constraints on the target certificate or attribute
+ * certificate.
+ * @throws InvalidAlgorithmParameterException if <code>trustAnchors</code>
+ * is empty.
+ * @throws NullPointerException if <code>trustAnchors</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements of
+ * <code>trustAnchors</code> is not of type
+ * <code>java.security.cert.TrustAnchor</code>
+ */
+ public ExtendedPKIXBuilderParameters(Set trustAnchors,
+ Selector targetConstraints)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ setTargetConstraints(targetConstraints);
+ }
+
+ /**
+ * Sets the maximum number of intermediate non-self-issued certificates in a
+ * certification path. The PKIX <code>CertPathBuilder</code> must not
+ * build paths longer then this length.
+ * <p>
+ * A value of 0 implies that the path can only contain a single certificate.
+ * A value of -1 does not limit the length. The default length is 5.
+ *
+ * <p>
+ *
+ * The basic constraints extension of a CA certificate overrides this value
+ * if smaller.
+ *
+ * @param maxPathLength the maximum number of non-self-issued intermediate
+ * certificates in the certification path
+ * @throws InvalidParameterException if <code>maxPathLength</code> is set
+ * to a value less than -1
+ *
+ * @see org.spongycastle.jce.provider.PKIXCertPathBuilderSpi
+ * @see #getMaxPathLength
+ */
+ public void setMaxPathLength(int maxPathLength)
+ {
+ if (maxPathLength < -1)
+ {
+ throw new InvalidParameterException("The maximum path "
+ + "length parameter can not be less than -1.");
+ }
+ this.maxPathLength = maxPathLength;
+ }
+
+ /**
+ * Returns the value of the maximum number of intermediate non-self-issued
+ * certificates in the certification path.
+ *
+ * @return the maximum number of non-self-issued intermediate certificates
+ * in the certification path, or -1 if no limit exists.
+ *
+ * @see #setMaxPathLength(int)
+ */
+ public int getMaxPathLength()
+ {
+ return maxPathLength;
+ }
+
+ /**
+ * Can alse handle <code>ExtendedPKIXBuilderParameters</code> and
+ * <code>PKIXBuilderParameters</code>.
+ *
+ * @param params Parameters to set.
+ * @see org.spongycastle.x509.ExtendedPKIXParameters#setParams(java.security.cert.PKIXParameters)
+ */
+ protected void setParams(PKIXParameters params)
+ {
+ super.setParams(params);
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ ExtendedPKIXBuilderParameters _params = (ExtendedPKIXBuilderParameters) params;
+ maxPathLength = _params.maxPathLength;
+ excludedCerts = new HashSet(_params.excludedCerts);
+ }
+ if (params instanceof PKIXBuilderParameters)
+ {
+ PKIXBuilderParameters _params = (PKIXBuilderParameters) params;
+ maxPathLength = _params.getMaxPathLength();
+ }
+ }
+
+ /**
+ * Makes a copy of this <code>PKIXParameters</code> object. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this <code>PKIXParameters</code> object
+ */
+ public Object clone()
+ {
+ ExtendedPKIXBuilderParameters params = null;
+ try
+ {
+ params = new ExtendedPKIXBuilderParameters(getTrustAnchors(),
+ getTargetConstraints());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(this);
+ return params;
+ }
+
+ /**
+ * Returns an instance of <code>ExtendedPKIXParameters</code> which can be
+ * safely casted to <code>ExtendedPKIXBuilderParameters</code>.
+ * <p>
+ * This method can be used to get a copy from other
+ * <code>PKIXBuilderParameters</code>, <code>PKIXParameters</code>,
+ * and <code>ExtendedPKIXParameters</code> instances.
+ *
+ * @param pkixParams The PKIX parameters to create a copy of.
+ * @return An <code>ExtendedPKIXBuilderParameters</code> instance.
+ */
+ public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+ {
+ ExtendedPKIXBuilderParameters params;
+ try
+ {
+ params = new ExtendedPKIXBuilderParameters(pkixParams
+ .getTrustAnchors(), X509CertStoreSelector
+ .getInstance((X509CertSelector) pkixParams
+ .getTargetCertConstraints()));
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(pkixParams);
+ return params;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXParameters.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXParameters.java
new file mode 100644
index 000000000..c2636c5b6
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXParameters.java
@@ -0,0 +1,647 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.Store;
+
+import java.security.InvalidAlgorithmParameterException;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import org.spongycastle.jce.cert.LDAPCertStoreParameters;
+import org.spongycastle.jce.cert.PKIXParameters;
+import org.spongycastle.jce.cert.TrustAnchor;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class extends the PKIXParameters with a validity model parameter.
+ */
+public class ExtendedPKIXParameters
+ extends PKIXParameters
+{
+
+ private List stores;
+
+ private Selector selector;
+
+ private boolean additionalLocationsEnabled;
+
+ private List additionalStores;
+
+ private Set trustedACIssuers;
+
+ private Set necessaryACAttributes;
+
+ private Set prohibitedACAttributes;
+
+ private Set attrCertCheckers;
+
+ /**
+ * Creates an instance of <code>PKIXParameters</code> with the specified
+ * <code>Set</code> of most-trusted CAs. Each element of the set is a
+ * {@link TrustAnchor TrustAnchor}. <p/> Note that the <code>Set</code>
+ * is copied to protect against subsequent modifications.
+ *
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+ * @throws InvalidAlgorithmParameterException if the specified
+ * <code>Set</code> is empty.
+ * @throws NullPointerException if the specified <code>Set</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements in the <code>Set</code>
+ * is not of type <code>java.security.cert.TrustAnchor</code>
+ */
+ public ExtendedPKIXParameters(Set trustAnchors)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ stores = new ArrayList();
+ additionalStores = new ArrayList();
+ trustedACIssuers = new HashSet();
+ necessaryACAttributes = new HashSet();
+ prohibitedACAttributes = new HashSet();
+ attrCertCheckers = new HashSet();
+ }
+
+ /**
+ * Returns an instance with the parameters of a given
+ * <code>PKIXParameters</code> object.
+ *
+ * @param pkixParams The given <code>PKIXParameters</code>
+ * @return an extended PKIX params object
+ */
+ public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+ {
+ ExtendedPKIXParameters params;
+ try
+ {
+ params = new ExtendedPKIXParameters(pkixParams.getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(pkixParams);
+ return params;
+ }
+
+ /**
+ * Method to support <code>clone()</code> under J2ME.
+ * <code>super.clone()</code> does not exist and fields are not copied.
+ *
+ * @param params Parameters to set. If this are
+ * <code>ExtendedPKIXParameters</code> they are copied to.
+ */
+ protected void setParams(PKIXParameters params)
+ {
+ setDate(params.getDate());
+ setCertPathCheckers(params.getCertPathCheckers());
+ setCertStores(params.getCertStores());
+ setAnyPolicyInhibited(params.isAnyPolicyInhibited());
+ setExplicitPolicyRequired(params.isExplicitPolicyRequired());
+ setPolicyMappingInhibited(params.isPolicyMappingInhibited());
+ setRevocationEnabled(params.isRevocationEnabled());
+ setInitialPolicies(params.getInitialPolicies());
+ setPolicyQualifiersRejected(params.getPolicyQualifiersRejected());
+ setSigProvider(params.getSigProvider());
+ setTargetCertConstraints(params.getTargetCertConstraints());
+ try
+ {
+ setTrustAnchors(params.getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ if (params instanceof ExtendedPKIXParameters)
+ {
+ ExtendedPKIXParameters _params = (ExtendedPKIXParameters) params;
+ validityModel = _params.validityModel;
+ useDeltas = _params.useDeltas;
+ additionalLocationsEnabled = _params.additionalLocationsEnabled;
+ selector = _params.selector == null ? null
+ : (Selector) _params.selector.clone();
+ stores = new ArrayList(_params.stores);
+ additionalStores = new ArrayList(_params.additionalStores);
+ trustedACIssuers = new HashSet(_params.trustedACIssuers);
+ prohibitedACAttributes = new HashSet(_params.prohibitedACAttributes);
+ necessaryACAttributes = new HashSet(_params.necessaryACAttributes);
+ attrCertCheckers = new HashSet(_params.attrCertCheckers);
+ }
+ }
+
+ /**
+ * This is the default PKIX validity model. Actually there are two variants
+ * of this: The PKIX model and the modified PKIX model. The PKIX model
+ * verifies that all involved certificates must have been valid at the
+ * current time. The modified PKIX model verifies that all involved
+ * certificates were valid at the signing time. Both are indirectly choosen
+ * with the {@link PKIXParameters#setDate(java.util.Date)} method, so this
+ * methods sets the Date when <em>all</em> certificates must have been
+ * valid.
+ */
+ public static final int PKIX_VALIDITY_MODEL = 0;
+
+ /**
+ * This model uses the following validity model. Each certificate must have
+ * been valid at the moment where is was used. That means the end
+ * certificate must have been valid at the time the signature was done. The
+ * CA certificate which signed the end certificate must have been valid,
+ * when the end certificate was signed. The CA (or Root CA) certificate must
+ * have been valid, when the CA certificate was signed and so on. So the
+ * {@link PKIXParameters#setDate(java.util.Date)} method sets the time, when
+ * the <em>end certificate</em> must have been valid. <p/> It is used e.g.
+ * in the German signature law.
+ */
+ public static final int CHAIN_VALIDITY_MODEL = 1;
+
+ private int validityModel = PKIX_VALIDITY_MODEL;
+
+ private boolean useDeltas = false;
+
+ /**
+ * Defaults to <code>false</code>.
+ *
+ * @return Returns if delta CRLs should be used.
+ */
+ public boolean isUseDeltasEnabled()
+ {
+ return useDeltas;
+ }
+
+ /**
+ * Sets if delta CRLs should be used for checking the revocation status.
+ *
+ * @param useDeltas <code>true</code> if delta CRLs should be used.
+ */
+ public void setUseDeltasEnabled(boolean useDeltas)
+ {
+ this.useDeltas = useDeltas;
+ }
+
+ /**
+ * @return Returns the validity model.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public int getValidityModel()
+ {
+ return validityModel;
+ }
+
+ /**
+ * Sets the Java CertStore to this extended PKIX parameters.
+ *
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>CertStore</code>.
+ */
+ public void setCertStores(List stores)
+ {
+ if (stores != null)
+ {
+ Iterator it = stores.iterator();
+ while (it.hasNext())
+ {
+ addCertStore((CertStore)it.next());
+ }
+ }
+ }
+
+ /**
+ * Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * The <code>List</code> is cloned.
+ *
+ * @param stores A list of stores to use.
+ * @see #getStores
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a {@link Store}.
+ */
+ public void setStores(List stores)
+ {
+ if (stores == null)
+ {
+ this.stores = new ArrayList();
+ }
+ else
+ {
+ for (Iterator i = stores.iterator(); i.hasNext();)
+ {
+ if (!(i.next() instanceof Store))
+ {
+ throw new ClassCastException(
+ "All elements of list must be "
+ + "of type org.spongycastle.util.Store.");
+ }
+ }
+ this.stores = new ArrayList(stores);
+ }
+ }
+
+ /**
+ * Adds a Bouncy Castle {@link Store} to find CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * This method should be used to add local stores, like collection based
+ * X.509 stores, if available. Local stores should be considered first,
+ * before trying to use additional (remote) locations, because they do not
+ * need possible additional network traffic.
+ * <p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ *
+ * @param store The store to add.
+ * @see #getStores
+ */
+ public void addStore(Store store)
+ {
+ if (stores != null)
+ {
+ stores.add(store);
+ }
+ }
+
+ /**
+ * Adds a additional Bouncy Castle {@link Store} to find CRLs, certificates,
+ * attribute certificates or cross certificates.
+ * <p>
+ * You should not use this method. This method is used for adding additional
+ * X.509 stores, which are used to add (remote) locations, e.g. LDAP, found
+ * during X.509 object processing, e.g. in certificates or CRLs. This method
+ * is used in PKIX certification path processing.
+ * <p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ *
+ * @param store The store to add.
+ * @see #getStores()
+ */
+ public void addAddionalStore(Store store)
+ {
+ if (store != null)
+ {
+ additionalStores.add(store);
+ }
+ }
+
+ /**
+ * Returns an immutable <code>List</code> of additional Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>List</code> of additional Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #addAddionalStore(Store)
+ */
+ public List getAdditionalStores()
+ {
+ return Collections.unmodifiableList(additionalStores);
+ }
+
+ /**
+ * Returns an immutable <code>List</code> of Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>List</code> of Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #setStores(List)
+ */
+ public List getStores()
+ {
+ return Collections.unmodifiableList(new ArrayList(stores));
+ }
+
+ /**
+ * @param validityModel The validity model to set.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public void setValidityModel(int validityModel)
+ {
+ this.validityModel = validityModel;
+ }
+
+ public Object clone()
+ {
+ ExtendedPKIXParameters params;
+ try
+ {
+ params = new ExtendedPKIXParameters(getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(this);
+ return params;
+ }
+
+ /**
+ * Returns if additional {@link X509Store}s for locations like LDAP found
+ * in certificates or CRLs should be used.
+ *
+ * @return Returns <code>true</code> if additional stores are used.
+ */
+ public boolean isAdditionalLocationsEnabled()
+ {
+ return additionalLocationsEnabled;
+ }
+
+ /**
+ * Sets if additional {@link X509Store}s for locations like LDAP found in
+ * certificates or CRLs should be used.
+ *
+ * @param enabled <code>true</code> if additional stores are used.
+ */
+ public void setAdditionalLocationsEnabled(boolean enabled)
+ {
+ additionalLocationsEnabled = enabled;
+ }
+
+ /**
+ * Returns the required constraints on the target certificate or attribute
+ * certificate. The constraints are returned as an instance of
+ * <code>Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ *
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * <p>
+ * Note that the <code>Selector</code> returned is cloned to protect
+ * against subsequent modifications.
+ *
+ * @return a <code>Selector</code> specifying the constraints on the
+ * target certificate or attribute certificate (or <code>null</code>)
+ * @see #setTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public Selector getTargetConstraints()
+ {
+ if (selector != null)
+ {
+ return (Selector) selector.clone();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate or attribute
+ * certificate. The constraints are specified as an instance of
+ * <code>Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * <p>
+ * Note that the <code>Selector</code> specified is cloned to protect
+ * against subsequent modifications.
+ *
+ * @param selector a <code>Selector</code> specifying the constraints on
+ * the target certificate or attribute certificate (or
+ * <code>null</code>)
+ * @see #getTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public void setTargetConstraints(Selector selector)
+ {
+ if (selector != null)
+ {
+ this.selector = (Selector) selector.clone();
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate. The constraints
+ * are specified as an instance of <code>X509CertSelector</code>. If
+ * <code>null</code>, no constraints are defined.
+ *
+ * <p>
+ * This method wraps the given <code>X509CertSelector</code> into a
+ * <code>X509CertStoreSelector</code>.
+ * <p>
+ * Note that the <code>X509CertSelector</code> specified is cloned to
+ * protect against subsequent modifications.
+ *
+ * @param selector a <code>X509CertSelector</code> specifying the
+ * constraints on the target certificate (or <code>null</code>)
+ * @see #getTargetCertConstraints
+ * @see X509CertStoreSelector
+ */
+ public void setTargetCertConstraints(CertSelector selector)
+ {
+ super.setTargetCertConstraints(selector);
+ if (selector != null)
+ {
+ this.selector = X509CertStoreSelector
+ .getInstance((X509CertSelector) selector);
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Returns the trusted attribute certificate issuers. If attribute
+ * certificates is verified the trusted AC issuers must be set.
+ * <p>
+ * The returned <code>Set</code> consists of <code>TrustAnchor</code>s.
+ * <p>
+ * The returned <code>Set</code> is immutable. Never <code>null</code>
+ *
+ * @return Returns an immutable set of the trusted AC issuers.
+ */
+ public Set getTrustedACIssuers()
+ {
+ return Collections.unmodifiableSet(trustedACIssuers);
+ }
+
+ /**
+ * Sets the trusted attribute certificate issuers. If attribute certificates
+ * is verified the trusted AC issuers must be set.
+ * <p>
+ * The <code>trustedACIssuers</code> must be a <code>Set</code> of
+ * <code>TrustAnchor</code>
+ * <p>
+ * The given set is cloned.
+ *
+ * @param trustedACIssuers The trusted AC issuers to set. Is never
+ * <code>null</code>.
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>TrustAnchor</code>.
+ */
+ public void setTrustedACIssuers(Set trustedACIssuers)
+ {
+ if (trustedACIssuers == null)
+ {
+ trustedACIssuers.clear();
+ return;
+ }
+ for (Iterator it = trustedACIssuers.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof TrustAnchor))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type " + TrustAnchor.class.getName() + ".");
+ }
+ }
+ this.trustedACIssuers.clear();
+ this.trustedACIssuers.addAll(trustedACIssuers);
+ }
+
+ /**
+ * Returns the neccessary attributes which must be contained in an attribute
+ * certificate.
+ * <p>
+ * The returned <code>Set</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ *
+ * @return Returns the necessary AC attributes.
+ */
+ public Set getNecessaryACAttributes()
+ {
+ return Collections.unmodifiableSet(necessaryACAttributes);
+ }
+
+ /**
+ * Sets the neccessary which must be contained in an attribute certificate.
+ * <p>
+ * The <code>Set</code> must contain <code>String</code>s with the
+ * OIDs.
+ * <p>
+ * The set is cloned.
+ *
+ * @param necessaryACAttributes The necessary AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>necessaryACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public void setNecessaryACAttributes(Set necessaryACAttributes)
+ {
+ if (necessaryACAttributes == null)
+ {
+ this.necessaryACAttributes.clear();
+ return;
+ }
+ for (Iterator it = necessaryACAttributes.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof String))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type String.");
+ }
+ }
+ this.necessaryACAttributes.clear();
+ this.necessaryACAttributes.addAll(necessaryACAttributes);
+ }
+
+ /**
+ * Returns the attribute certificates which are not allowed.
+ * <p>
+ * The returned <code>Set</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ *
+ * @return Returns the prohibited AC attributes. Is never <code>null</code>.
+ */
+ public Set getProhibitedACAttributes()
+ {
+ return prohibitedACAttributes;
+ }
+
+ /**
+ * Sets the attribute certificates which are not allowed.
+ * <p>
+ * The <code>Set</code> must contain <code>String</code>s with the
+ * OIDs.
+ * <p>
+ * The set is cloned.
+ *
+ * @param prohibitedACAttributes The prohibited AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>prohibitedACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public void setProhibitedACAttributes(Set prohibitedACAttributes)
+ {
+ if (prohibitedACAttributes == null)
+ {
+ this.prohibitedACAttributes.clear();
+ return;
+ }
+ for (Iterator it = prohibitedACAttributes.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof String))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type String.");
+ }
+ }
+ this.prohibitedACAttributes.clear();
+ this.prohibitedACAttributes.addAll(prohibitedACAttributes);
+ }
+
+ /**
+ * Returns the attribute certificate checker. The returned set contains
+ * {@link PKIXAttrCertChecker}s and is immutable.
+ *
+ * @return Returns the attribute certificate checker. Is never
+ * <code>null</code>.
+ */
+ public Set getAttrCertCheckers()
+ {
+ return Collections.unmodifiableSet(attrCertCheckers);
+ }
+
+ /**
+ * Sets the attribute certificate checkers.
+ * <p>
+ * All elements in the <code>Set</code> must a {@link PKIXAttrCertChecker}.
+ * <p>
+ * The given set is cloned.
+ *
+ * @param attrCertCheckers The attribute certificate checkers to set. Is
+ * never <code>null</code>.
+ * @throws ClassCastException if an element of <code>attrCertCheckers</code>
+ * is not a <code>PKIXAttrCertChecker</code>.
+ */
+/*
+ public void setAttrCertCheckers(Set attrCertCheckers)
+ {
+ if (attrCertCheckers == null)
+ {
+ this.attrCertCheckers.clear();
+ return;
+ }
+ for (Iterator it = attrCertCheckers.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof PKIXAttrCertChecker))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type " + PKIXAttrCertChecker.class.getName() + ".");
+ }
+ }
+ this.attrCertCheckers.clear();
+ this.attrCertCheckers.addAll(attrCertCheckers);
+ }
+*/
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509AttributeCertStoreSelector.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509AttributeCertStoreSelector.java
new file mode 100644
index 000000000..b47236d1b
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509AttributeCertStoreSelector.java
@@ -0,0 +1,486 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.Target;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.Targets;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Selector;
+
+/**
+ * This class is an <code>Selector</code> like implementation to select
+ * attribute certificates from a given set of criteria.
+ *
+ * @see org.spongycastle.x509.X509AttributeCertificate
+ * @see org.spongycastle.x509.X509Store
+ */
+public class X509AttributeCertStoreSelector
+ implements Selector
+{
+
+ // TODO: name constraints???
+
+ private AttributeCertificateHolder holder;
+
+ private AttributeCertificateIssuer issuer;
+
+ private BigInteger serialNumber;
+
+ private Date attributeCertificateValid;
+
+ private X509AttributeCertificate attributeCert;
+
+ private Collection targetNames = new HashSet();
+
+ private Collection targetGroups = new HashSet();
+
+ public X509AttributeCertStoreSelector()
+ {
+ super();
+ }
+
+ /**
+ * Decides if the given attribute certificate should be selected.
+ *
+ * @param obj The attribute certificate which should be checked.
+ * @return <code>true</code> if the attribute certificate can be selected,
+ * <code>false</code> otherwise.
+ */
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509AttributeCertificate))
+ {
+ return false;
+ }
+
+ X509AttributeCertificate attrCert = (X509AttributeCertificate) obj;
+
+ if (this.attributeCert != null)
+ {
+ if (!this.attributeCert.equals(attrCert))
+ {
+ return false;
+ }
+ }
+ if (serialNumber != null)
+ {
+ if (!attrCert.getSerialNumber().equals(serialNumber))
+ {
+ return false;
+ }
+ }
+ if (holder != null)
+ {
+ if (!attrCert.getHolder().equals(holder))
+ {
+ return false;
+ }
+ }
+ if (issuer != null)
+ {
+ if (!attrCert.getIssuer().equals(issuer))
+ {
+ return false;
+ }
+ }
+
+ if (attributeCertificateValid != null)
+ {
+ try
+ {
+ attrCert.checkValidity(attributeCertificateValid);
+ }
+ catch (CertificateExpiredException e)
+ {
+ return false;
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ return false;
+ }
+ }
+ if (!targetNames.isEmpty() || !targetGroups.isEmpty())
+ {
+
+ byte[] targetInfoExt = attrCert
+ .getExtensionValue(X509Extensions.TargetInformation.getId());
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation
+ .getInstance(new ASN1InputStream(
+ ((DEROctetString) DEROctetString
+ .fromByteArray(targetInfoExt)).getOctets())
+ .readObject());
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+ Targets[] targetss = targetinfo.getTargetsObjects();
+ if (!targetNames.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetNames.contains(targets[j]
+ .getTargetName()))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ if (!targetGroups.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetGroups.contains(targets[j]
+ .getTargetGroup()))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return the clone.
+ */
+ public Object clone()
+ {
+ X509AttributeCertStoreSelector sel = new X509AttributeCertStoreSelector();
+ sel.attributeCert = attributeCert;
+ sel.attributeCertificateValid = getAttributeCertificateValid();
+ sel.holder = holder;
+ sel.issuer = issuer;
+ sel.serialNumber = serialNumber;
+ sel.targetGroups = getTargetGroups();
+ sel.targetNames = getTargetNames();
+ return sel;
+ }
+
+ /**
+ * Returns the attribute certificate which must be matched.
+ *
+ * @return Returns the attribute certificate.
+ */
+ public X509AttributeCertificate getAttributeCert()
+ {
+ return attributeCert;
+ }
+
+ /**
+ * Set the attribute certificate to be matched. If <code>null</code> is
+ * given any will do.
+ *
+ * @param attributeCert The attribute certificate to set.
+ */
+ public void setAttributeCert(X509AttributeCertificate attributeCert)
+ {
+ this.attributeCert = attributeCert;
+ }
+
+ /**
+ * Get the criteria for the validity.
+ *
+ * @return Returns the attributeCertificateValid.
+ */
+ public Date getAttributeCertificateValid()
+ {
+ if (attributeCertificateValid != null)
+ {
+ return new Date(attributeCertificateValid.getTime());
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the time, when the certificate must be valid. If <code>null</code>
+ * is given any will do.
+ *
+ * @param attributeCertificateValid The attribute certificate validation
+ * time to set.
+ */
+ public void setAttributeCertificateValid(Date attributeCertificateValid)
+ {
+ if (attributeCertificateValid != null)
+ {
+ this.attributeCertificateValid = new Date(attributeCertificateValid
+ .getTime());
+ }
+ else
+ {
+ this.attributeCertificateValid = null;
+ }
+ }
+
+ /**
+ * Gets the holder.
+ *
+ * @return Returns the holder.
+ */
+ public AttributeCertificateHolder getHolder()
+ {
+ return holder;
+ }
+
+ /**
+ * Sets the holder. If <code>null</code> is given any will do.
+ *
+ * @param holder The holder to set.
+ */
+ public void setHolder(AttributeCertificateHolder holder)
+ {
+ this.holder = holder;
+ }
+
+ /**
+ * Returns the issuer criterion.
+ *
+ * @return Returns the issuer.
+ */
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return issuer;
+ }
+
+ /**
+ * Sets the issuer the attribute certificate must have. If <code>null</code>
+ * is given any will do.
+ *
+ * @param issuer The issuer to set.
+ */
+ public void setIssuer(AttributeCertificateIssuer issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ /**
+ * Gets the serial number the attribute certificate must have.
+ *
+ * @return Returns the serialNumber.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ /**
+ * Sets the serial number the attribute certificate must have. If
+ * <code>null</code> is given any will do.
+ *
+ * @param serialNumber The serialNumber to set.
+ */
+ public void setSerialNumber(BigInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name The name as a GeneralName (not <code>null</code>)
+ */
+ public void addTargetName(GeneralName name)
+ {
+ targetNames.add(name);
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void addTargetName(byte[] name) throws IOException
+ {
+ addTargetName(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target names criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of either GeneralName objects or byte[] arrays representing
+ * DER encoded GeneralName structures.
+ *
+ * @param names A collection of target names.
+ * @throws IOException if a parsing error occurs.
+ * @see #addTargetName(byte[])
+ * @see #addTargetName(GeneralName)
+ */
+ public void setTargetNames(Collection names) throws IOException
+ {
+ targetNames = extractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target names. The collection consists of <code>List</code>s
+ * made up of an <code>Integer</code> in the first entry and a DER encoded
+ * byte array or a <code>String</code> in the second entry.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ * @see #setTargetNames(Collection)
+ */
+ public Collection getTargetNames()
+ {
+ return Collections.unmodifiableCollection(targetNames);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param group The group as GeneralName form (not <code>null</code>)
+ */
+ public void addTargetGroup(GeneralName group)
+ {
+ targetGroups.add(group);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void addTargetGroup(byte[] name) throws IOException
+ {
+ addTargetGroup(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target groups criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER
+ * encoded GeneralNames.
+ *
+ * @param names A collection of target groups.
+ * @throws IOException if a parsing error occurs.
+ * @see #addTargetGroup(byte[])
+ * @see #addTargetGroup(GeneralName)
+ */
+ public void setTargetGroups(Collection names) throws IOException
+ {
+ targetGroups = extractGeneralNames(names);
+ }
+
+
+
+ /**
+ * Gets the target groups. The collection consists of <code>List</code>s
+ * made up of an <code>Integer</code> in the first entry and a DER encoded
+ * byte array or a <code>String</code> in the second entry.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ * @see #setTargetGroups(Collection)
+ */
+ public Collection getTargetGroups()
+ {
+ return Collections.unmodifiableCollection(targetGroups);
+ }
+
+ private Set extractGeneralNames(Collection names)
+ throws IOException
+ {
+ if (names == null || names.isEmpty())
+ {
+ return new HashSet();
+ }
+ Set temp = new HashSet();
+ for (Iterator it = names.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+ if (o instanceof GeneralName)
+ {
+ temp.add(o);
+ }
+ else
+ {
+ temp.add(GeneralName.getInstance(ASN1Primitive.fromByteArray((byte[])o)));
+ }
+ }
+ return temp;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509CRLStoreSelector.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509CRLStoreSelector.java
new file mode 100644
index 000000000..bb8cf600c
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509CRLStoreSelector.java
@@ -0,0 +1,330 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRL;
+import java.security.cert.X509CRL;
+import org.spongycastle.jce.cert.X509CRLSelector;
+
+/**
+ * This class is a Selector implementation for X.509 certificate revocation
+ * lists.
+ *
+ * @see org.spongycastle.util.Selector
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.jce.provider.X509StoreCRLCollection
+ */
+public class X509CRLStoreSelector
+ extends X509CRLSelector
+ implements Selector
+{
+ private boolean deltaCRLIndicator = false;
+
+ private boolean completeCRLEnabled = false;
+
+ private BigInteger maxBaseCRLNumber = null;
+
+ private byte[] issuingDistributionPoint = null;
+
+ private boolean issuingDistributionPointEnabled = false;
+
+ private X509AttributeCertificate attrCertChecking;
+
+ /**
+ * Returns if the issuing distribution point criteria should be applied.
+ * Defaults to <code>false</code>.
+ * <p>
+ * You may also set the issuing distribution point criteria if not a missing
+ * issuing distribution point should be assumed.
+ *
+ * @return Returns if the issuing distribution point check is enabled.
+ */
+ public boolean isIssuingDistributionPointEnabled()
+ {
+ return issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Enables or disables the issuing distribution point check.
+ *
+ * @param issuingDistributionPointEnabled <code>true</code> to enable the
+ * issuing distribution point check.
+ */
+ public void setIssuingDistributionPointEnabled(
+ boolean issuingDistributionPointEnabled)
+ {
+ this.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Sets the attribute certificate being checked. This is not a criterion.
+ * Rather, it is optional information that may help a {@link X509Store} find
+ * CRLs that would be relevant when checking revocation for the specified
+ * attribute certificate. If <code>null</code> is specified, then no such
+ * optional information is provided.
+ *
+ * @param attrCert the <code>X509AttributeCertificate</code> being checked (or
+ * <code>null</code>)
+ * @see #getAttrCertificateChecking()
+ */
+ public void setAttrCertificateChecking(X509AttributeCertificate attrCert)
+ {
+ attrCertChecking = attrCert;
+ }
+
+ /**
+ * Returns the attribute certificate being checked.
+ *
+ * @return Returns the attribute certificate being checked.
+ * @see #setAttrCertificateChecking(X509AttributeCertificate)
+ */
+ public X509AttributeCertificate getAttrCertificateChecking()
+ {
+ return attrCertChecking;
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509CRL))
+ {
+ return false;
+ }
+ X509CRL crl = (X509CRL)obj;
+ DERInteger dci = null;
+ try
+ {
+ byte[] bytes = crl
+ .getExtensionValue(X509Extensions.DeltaCRLIndicator.getId());
+ if (bytes != null)
+ {
+ dci = DERInteger.getInstance(X509ExtensionUtil
+ .fromExtensionValue(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ if (isDeltaCRLIndicatorEnabled())
+ {
+ if (dci == null)
+ {
+ return false;
+ }
+ }
+ if (isCompleteCRLEnabled())
+ {
+ if (dci != null)
+ {
+ return false;
+ }
+ }
+ if (dci != null)
+ {
+
+ if (maxBaseCRLNumber != null)
+ {
+ if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1)
+ {
+ return false;
+ }
+ }
+ }
+ if (issuingDistributionPointEnabled)
+ {
+ byte[] idp = crl
+ .getExtensionValue(X509Extensions.IssuingDistributionPoint
+ .getId());
+ if (issuingDistributionPoint == null)
+ {
+ if (idp != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!Arrays.areEqual(idp, issuingDistributionPoint))
+ {
+ return false;
+ }
+ }
+
+ }
+ return super.match((X509CRL)obj);
+ }
+
+ public boolean match(CRL crl)
+ {
+ return match((Object)crl);
+ }
+
+ /**
+ * Returns if this selector must match CRLs with the delta CRL indicator
+ * extension set. Defaults to <code>false</code>.
+ *
+ * @return Returns <code>true</code> if only CRLs with the delta CRL
+ * indicator extension are selected.
+ */
+ public boolean isDeltaCRLIndicatorEnabled()
+ {
+ return deltaCRLIndicator;
+ }
+
+ /**
+ * If this is set to <code>true</code> the CRL reported contains the delta
+ * CRL indicator CRL extension.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator
+ * extension must be in the CRL.
+ */
+ public void setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator)
+ {
+ this.deltaCRLIndicator = deltaCRLIndicator;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CRLSelector</code>.
+ *
+ * @param selector A <code>X509CRLSelector</code> instance.
+ * @return An instance of an <code>X509CRLStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation
+ * fails.
+ */
+ public static X509CRLStoreSelector getInstance(X509CRLSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException(
+ "cannot create from null selector");
+ }
+ X509CRLStoreSelector cs = new X509CRLStoreSelector();
+ cs.setCertificateChecking(selector.getCertificateChecking());
+ cs.setDateAndTime(selector.getDateAndTime());
+ try
+ {
+ cs.setIssuerNames(selector.getIssuerNames());
+ }
+ catch (IOException e)
+ {
+ // cannot happen
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ //cs.setIssuers(selector.getIssuers());
+ cs.setMaxCRLNumber(selector.getMaxCRL());
+ cs.setMinCRLNumber(selector.getMinCRL());
+ return cs;
+ }
+
+ public Object clone()
+ {
+ X509CRLStoreSelector sel = X509CRLStoreSelector.getInstance(this);
+ sel.deltaCRLIndicator = deltaCRLIndicator;
+ sel.completeCRLEnabled = completeCRLEnabled;
+ sel.maxBaseCRLNumber = maxBaseCRLNumber;
+ sel.attrCertChecking = attrCertChecking;
+ sel.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ sel.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ return sel;
+ }
+
+ /**
+ * If <code>true</code> only complete CRLs are returned. Defaults to
+ * <code>false</code>.
+ *
+ * @return <code>true</code> if only complete CRLs are returned.
+ */
+ public boolean isCompleteCRLEnabled()
+ {
+ return completeCRLEnabled;
+ }
+
+ /**
+ * If set to <code>true</code> only complete CRLs are returned.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param completeCRLEnabled <code>true</code> if only complete CRLs
+ * should be returned.
+ */
+ public void setCompleteCRLEnabled(boolean completeCRLEnabled)
+ {
+ this.completeCRLEnabled = completeCRLEnabled;
+ }
+
+ /**
+ * Get the maximum base CRL number. Defaults to <code>null</code>.
+ *
+ * @return Returns the maximum base CRL number.
+ * @see #setMaxBaseCRLNumber(BigInteger)
+ */
+ public BigInteger getMaxBaseCRLNumber()
+ {
+ return maxBaseCRLNumber;
+ }
+
+ /**
+ * Sets the maximum base CRL number. Setting to <code>null</code> disables
+ * this cheack.
+ * <p>
+ * This is only meaningful for delta CRLs. Complete CRLs must have a CRL
+ * number which is greater or equal than the base number of the
+ * corresponding CRL.
+ *
+ * @param maxBaseCRLNumber The maximum base CRL number to set.
+ */
+ public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber)
+ {
+ this.maxBaseCRLNumber = maxBaseCRLNumber;
+ }
+
+ /**
+ * Returns the issuing distribution point. Defaults to <code>null</code>,
+ * which is a missing issuing distribution point extension.
+ * <p>
+ * The internal byte array is cloned before it is returned.
+ * <p>
+ * The criteria must be enable with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @return Returns the issuing distribution point.
+ * @see #setIssuingDistributionPoint(byte[])
+ */
+ public byte[] getIssuingDistributionPoint()
+ {
+ return Arrays.clone(issuingDistributionPoint);
+ }
+
+ /**
+ * Sets the issuing distribution point.
+ * <p>
+ * The issuing distribution point extension is a CRL extension which
+ * identifies the scope and the distribution point of a CRL. The scope
+ * contains among others information about revocation reasons contained in
+ * the CRL. Delta CRLs and complete CRLs must have matching issuing
+ * distribution points.
+ * <p>
+ * The byte array is cloned to protect against subsequent modifications.
+ * <p>
+ * You must also enable or disable this criteria with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @param issuingDistributionPoint The issuing distribution point to set.
+ * This is the DER encoded OCTET STRING extension value.
+ * @see #getIssuingDistributionPoint()
+ */
+ public void setIssuingDistributionPoint(byte[] issuingDistributionPoint)
+ {
+ this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509CertStoreSelector.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509CertStoreSelector.java
new file mode 100644
index 000000000..f4efcddbc
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509CertStoreSelector.java
@@ -0,0 +1,86 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.io.IOException;
+import java.security.cert.Certificate;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+
+/**
+ * This class is a Selector implementation for X.509 certificates.
+ *
+ * @see org.spongycastle.util.Selector
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.jce.provider.X509StoreCertCollection
+ */
+public class X509CertStoreSelector
+ extends X509CertSelector
+ implements Selector
+{
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate other = (X509Certificate)obj;
+
+ return super.match(other);
+ }
+
+ public boolean match(Certificate cert)
+ {
+ return match((Object)cert);
+ }
+
+ public Object clone()
+ {
+ X509CertStoreSelector selector = (X509CertStoreSelector)super.clone();
+
+ return selector;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CertSelector</code>.
+ *
+ * @param selector A <code>X509CertSelector</code> instance.
+ * @return An instance of an <code>X509CertStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation fails.
+ */
+ public static X509CertStoreSelector getInstance(X509CertSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException("cannot create from null selector");
+ }
+ X509CertStoreSelector cs = new X509CertStoreSelector();
+ cs.setAuthorityKeyIdentifier(selector.getAuthorityKeyIdentifier());
+ cs.setBasicConstraints(selector.getBasicConstraints());
+ cs.setCertificate(selector.getCertificate());
+ cs.setCertificateValid(selector.getCertificateValid());
+ cs.setMatchAllSubjectAltNames(selector.getMatchAllSubjectAltNames());
+ try
+ {
+ cs.setPathToNames(selector.getPathToNames());
+ cs.setExtendedKeyUsage(selector.getExtendedKeyUsage());
+ //cs.setNameConstraints(selector.getNameConstraints());
+ cs.setPolicy(selector.getPolicy());
+ cs.setSubjectPublicKeyAlgID(selector.getSubjectPublicKeyAlgID());
+ cs.setSubject(selector.getSubjectAsBytes());
+ cs.setIssuer(selector.getIssuerAsBytes());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error in passed in selector: " + e);
+ }
+ cs.setKeyUsage(selector.getKeyUsage());
+ cs.setPrivateKeyValid(selector.getPrivateKeyValid());
+ cs.setSerialNumber(selector.getSerialNumber());
+ cs.setSubjectKeyIdentifier(selector.getSubjectKeyIdentifier());
+ cs.setSubjectPublicKey(selector.getSubjectPublicKey());
+ return cs;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509Util.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509Util.java
new file mode 100644
index 000000000..3b249ac8f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509Util.java
@@ -0,0 +1,397 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.Strings;
+
+class X509Util
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull());
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull());
+ params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull());
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, new DERNull());
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, new DERNull());
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ static DERObjectIdentifier getAlgorithmOID(
+ String algorithmName)
+ {
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (algorithms.containsKey(algorithmName))
+ {
+ return (DERObjectIdentifier)algorithms.get(algorithmName);
+ }
+
+ return new DERObjectIdentifier(algorithmName);
+ }
+
+ static AlgorithmIdentifier getSigAlgID(
+ DERObjectIdentifier sigOid,
+ String algorithmName)
+ {
+ if (noParams.contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (params.containsKey(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ return new AlgorithmIdentifier(sigOid, new DERNull());
+ }
+ }
+
+ static Iterator getAlgNames()
+ {
+ Enumeration e = algorithms.keys();
+ List l = new ArrayList();
+
+ while (e.hasMoreElements())
+ {
+ l.add(e.nextElement());
+ }
+
+ return l.iterator();
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm);
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm,
+ String provider)
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ if (provider != null)
+ {
+ return Signature.getInstance(algorithm, provider);
+ }
+ else
+ {
+ return Signature.getInstance(algorithm);
+ }
+ }
+
+ static byte[] calculateSignature(
+ DERObjectIdentifier sigOid,
+ String sigName,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName);
+
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static byte[] calculateSignature(
+ DERObjectIdentifier sigOid,
+ String sigName,
+ String provider,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName, provider);
+
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static class Implementation
+ {
+ Object engine;
+ Provider provider;
+
+ Implementation(
+ Object engine,
+ Provider provider)
+ {
+ this.engine = engine;
+ this.provider = provider;
+ }
+
+ Object getEngine()
+ {
+ return engine;
+ }
+
+ Provider getProvider()
+ {
+ return provider;
+ }
+ }
+
+ /**
+ * see if we can find an algorithm (or its alias and what it represents) in
+ * the property table for the given provider.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm,
+ Provider prov)
+ throws NoSuchAlgorithmException
+ {
+ algorithm = Strings.toUpperCase(algorithm);
+
+ String alias;
+
+ while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null)
+ {
+ algorithm = alias;
+ }
+
+ String className = prov.getProperty(baseName + "." + algorithm);
+
+ if (className != null)
+ {
+ try
+ {
+ Class cls;
+ ClassLoader clsLoader = prov.getClass().getClassLoader();
+
+ if (clsLoader != null)
+ {
+ cls = clsLoader.loadClass(className);
+ }
+ else
+ {
+ cls = Class.forName(className);
+ }
+
+ return new Implementation(cls.newInstance(), prov);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!");
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!");
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm + " for provider " + prov.getName());
+ }
+
+ /**
+ * return an implementation for a given algorithm/provider.
+ * If the provider is null, we grab the first avalaible who has the required algorithm.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ Provider[] prov = Security.getProviders();
+
+ //
+ // search every provider looking for the algorithm we want.
+ //
+ for (int i = 0; i != prov.length; i++)
+ {
+ //
+ // try case insensitive
+ //
+ Implementation imp = getImplementation(baseName, Strings.toUpperCase(algorithm), prov[i]);
+ if (imp != null)
+ {
+ return imp;
+ }
+
+ try
+ {
+ imp = getImplementation(baseName, algorithm, prov[i]);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // continue
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm);
+ }
+
+ static Provider getProvider(String provider)
+ throws NoSuchProviderException
+ {
+ Provider prov = Security.getProvider(provider);
+
+ if (prov == null)
+ {
+ throw new NoSuchProviderException("Provider " + provider + " not found");
+ }
+
+ return prov;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V1CertificateGenerator.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V1CertificateGenerator.java
new file mode 100644
index 000000000..40e2d4272
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V1CertificateGenerator.java
@@ -0,0 +1,341 @@
+package org.spongycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ * @deprecated use org.spongycastle.cert.X509v1CertificateBuilder.
+ */
+public class X509V1CertificateGenerator
+{
+ private V1TBSCertificateGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+
+ public X509V1CertificateGenerator()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+ new ByteArrayInputStream(key.getEncoded())).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC" and the passed in source of randomness
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider and the passed in source of randomness
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateEncodingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ try
+ {
+ return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V2CRLGenerator.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V2CRLGenerator.java
new file mode 100644
index 000000000..5b1c8e4f9
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V2CRLGenerator.java
@@ -0,0 +1,432 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V2TBSCertListGenerator;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.X509CRLObject;
+
+/**
+ * class to produce an X.509 Version 2 CRL.
+ * @deprecated use org.spongycastle.cert.X509v2CRLBuilder.
+ */
+public class X509V2CRLGenerator
+{
+ private V2TBSCertListGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V2CRLGenerator()
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setThisUpdate(
+ Date date)
+ {
+ tbsGen.setThisUpdate(new Time(date));
+ }
+
+ public void setNextUpdate(
+ Date date)
+ {
+ tbsGen.setNextUpdate(new Time(date));
+ }
+
+ /**
+ * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise
+ * or 0 if CRLReason is not to be used
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason);
+ }
+
+ /**
+ * Add a CRL entry with an Invalidity Date extension as well as a CRLReason extension.
+ * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise
+ * or 0 if CRLReason is not to be used
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason, Date invalidityDate)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason, new ASN1GeneralizedTime(invalidityDate));
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, X509Extensions extensions)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), Extensions.getInstance(extensions));
+ }
+
+ /**
+ * Add the CRLEntry objects contained in a previous CRL.
+ *
+ * @param other the X509CRL to source the other entries from.
+ */
+ public void addCRL(X509CRL other)
+ throws CRLException
+ {
+ Set revocations = other.getRevokedCertificates();
+
+ if (revocations != null)
+ {
+ Iterator it = revocations.iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntry entry = (X509CRLEntry)it.next();
+
+ ASN1InputStream aIn = new ASN1InputStream(entry.getEncoded());
+
+ try
+ {
+ tbsGen.addCRLEntry(ASN1Sequence.getInstance(aIn.readObject()));
+ }
+ catch (IOException e)
+ {
+ throw new CRLException("exception processing encoding of CRL: " + e.toString());
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509CRL(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider "SC" and an user defined SecureRandom object as
+ * source of randomness.
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509CRL(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509CRL(key, provider, null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509CRL generate(
+ PrivateKey key)
+ throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider and an user defined SecureRandom object as
+ * source of randomness.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertList tbsCrl = generateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCRLException("cannot generate CRL encoding", e);
+ }
+
+ return generateJcaObject(tbsCrl, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the passed in provider for the signing.
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ String provider)
+ throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertList tbsCrl = generateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCRLException("cannot generate CRL encoding", e);
+ }
+
+ return generateJcaObject(tbsCrl, signature);
+ }
+
+ private TBSCertList generateCertList()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertList();
+ }
+
+ private X509CRL generateJcaObject(TBSCertList tbsCrl, byte[] signature)
+ throws CRLException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCrl);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CRLObject(new CertificateList(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+
+ private static class ExtCRLException
+ extends CRLException
+ {
+ Throwable cause;
+
+ ExtCRLException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V3CertificateGenerator.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V3CertificateGenerator.java
new file mode 100644
index 000000000..716e5dd23
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/X509V3CertificateGenerator.java
@@ -0,0 +1,491 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V3TBSCertificateGenerator;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.provider.X509CertificateObject;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ * @deprecated use org.spongycastle.cert.X509v3CertificateBuilder.
+ */
+public class X509V3CertificateGenerator
+{
+ private V3TBSCertificateGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V3CertificateGenerator()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo.getInstance(new ASN1InputStream(key.getEncoded()).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * Set the subject unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setSubjectUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setSubjectUniqueID(booleanToBitString(uniqueID));
+ }
+
+ /**
+ * Set the issuer unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setIssuerUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setIssuerUniqueID(booleanToBitString(uniqueID));
+ }
+
+ private DERBitString booleanToBitString(boolean[] id)
+ {
+ byte[] bytes = new byte[(id.length + 7) / 8];
+
+ for (int i = 0; i != id.length; i++)
+ {
+ bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0;
+ }
+
+ int pad = id.length % 8;
+
+ if (pad == 0)
+ {
+ return new DERBitString(bytes);
+ }
+ else
+ {
+ return new DERBitString(bytes, 8 - pad);
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ String oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extValue = cert.getExtensionValue(oid);
+
+ if (extValue == null)
+ {
+ throw new CertificateParsingException("extension " + oid + " not present");
+ }
+
+ try
+ {
+ ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue);
+
+ this.addExtension(oid, critical, value);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateParsingException(e.toString());
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ this.copyAndAddExtension(oid.getId(), critical, cert);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC", and the passed in source of randomness
+ * (if required).
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider, and the passed in source of randomness
+ * (if required).
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private TBSCertificate generateTbsCert()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertificate();
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateParsingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/examples/AttrCertExample.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/examples/AttrCertExample.java
new file mode 100644
index 000000000..8e9a5ec05
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/x509/examples/AttrCertExample.java
@@ -0,0 +1,290 @@
+package org.spongycastle.x509.examples;
+
+import java.security.cert.*;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.*;
+import java.math.*;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.*;
+import org.spongycastle.asn1.*;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.x509.*;
+
+/**
+ * A simple exmple that generates an attribute certificate.
+ */
+public class AttrCertExample
+{
+ static X509V1CertificateGenerator v1CertGen = new X509V1CertificateGenerator();
+ static X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
+
+ /**
+ * we generate the CA's certificate
+ */
+ public static X509Certificate createCaCert(
+ PublicKey pubKey,
+ PrivateKey privKey)
+ throws Exception
+ {
+ //
+ // signers name
+ //
+ String issuer = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+ //
+ // subjects name - the same as we are self signed.
+ //
+ String subject = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+ //
+ // create the certificate - version 1
+ //
+
+ v1CertGen.setSerialNumber(BigInteger.valueOf(10));
+ v1CertGen.setIssuerDN(new X509Principal(issuer));
+ v1CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
+ v1CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)));
+ v1CertGen.setSubjectDN(new X509Principal(subject));
+ v1CertGen.setPublicKey(pubKey);
+ v1CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ X509Certificate cert = v1CertGen.generateX509Certificate(privKey);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(pubKey);
+
+ return cert;
+ }
+
+ /**
+ * we generate a certificate signed by our CA's intermediate certficate
+ */
+ public static X509Certificate createClientCert(
+ PublicKey pubKey,
+ PrivateKey caPrivKey,
+ PublicKey caPubKey)
+ throws Exception
+ {
+ //
+ // issuer
+ //
+ String issuer = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+ //
+ // subjects name table.
+ //
+ Hashtable attrs = new Hashtable();
+ Vector order = new Vector();
+
+ attrs.put(X509Principal.C, "AU");
+ attrs.put(X509Principal.O, "The Legion of the Bouncy Castle");
+ attrs.put(X509Principal.L, "Melbourne");
+ attrs.put(X509Principal.CN, "Eric H. Echidna");
+ attrs.put(X509Principal.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+ order.addElement(X509Principal.C);
+ order.addElement(X509Principal.O);
+ order.addElement(X509Principal.L);
+ order.addElement(X509Principal.CN);
+ order.addElement(X509Principal.EmailAddress);
+
+ //
+ // create the certificate - version 3
+ //
+ v3CertGen.reset();
+
+ v3CertGen.setSerialNumber(BigInteger.valueOf(20));
+ v3CertGen.setIssuerDN(new X509Principal(issuer));
+ v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
+ v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30)));
+ v3CertGen.setSubjectDN(new X509Principal(order, attrs));
+ v3CertGen.setPublicKey(pubKey);
+ v3CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ //
+ // add the extensions
+ //
+
+ v3CertGen.addExtension(
+ MiscObjectIdentifiers.netscapeCertType,
+ false,
+ new NetscapeCertType(NetscapeCertType.objectSigning | NetscapeCertType.smime));
+
+ X509Certificate cert = v3CertGen.generateX509Certificate(caPrivKey);
+
+ cert.checkValidity(new Date());
+
+ cert.verify(caPubKey);
+
+ return cert;
+ }
+
+ public static void main(String args[])
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ //
+ // personal keys
+ //
+ RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+ new BigInteger("11", 16),
+ new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+ new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+ new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+ new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+ new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+ new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+ //
+ // ca keys
+ //
+ RSAPublicKeySpec caPubKeySpec = new RSAPublicKeySpec(
+ new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+ new BigInteger("11", 16));
+
+ RSAPrivateCrtKeySpec caPrivKeySpec = new RSAPrivateCrtKeySpec(
+ new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+ new BigInteger("11", 16),
+ new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16),
+ new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16),
+ new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16),
+ new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16),
+ new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16),
+ new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16));
+
+ //
+ // set up the keys
+ //
+ KeyFactory fact = KeyFactory.getInstance("RSA", "SC");
+ PrivateKey caPrivKey = fact.generatePrivate(caPrivKeySpec);
+ PublicKey caPubKey = fact.generatePublic(caPubKeySpec);
+ PrivateKey privKey = fact.generatePrivate(privKeySpec);
+ PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+ //
+ // note in this case we are using the CA certificate for both the client cetificate
+ // and the attribute certificate. This is to make the vcode simpler to read, in practice
+ // the CA for the attribute certificate should be different to that of the client certificate
+ //
+ X509Certificate caCert = createCaCert(caPubKey, caPrivKey);
+ X509Certificate clientCert = createClientCert(pubKey, caPrivKey, caPubKey);
+
+ // Einen neuen Attributzertifikatsgenerator instantiieren
+ X509V2AttributeCertificateGenerator acGen = new X509V2AttributeCertificateGenerator();
+
+ acGen.reset();
+
+ /*
+ * Holder setzen hier als IssuerSerial Issuer und Serial sind ein
+ * eindeutiger Schl�ssel f�r ein Client Zertifikat!
+ */
+
+ acGen.setHolder(new AttributeCertificateHolder(clientCert));
+
+ // Issuer setzen
+
+ acGen.setIssuer(new AttributeCertificateIssuer(PrincipalUtil.getSubjectX509Principal(caCert)));
+
+ // Serial Number (frei gew�hlt)
+ acGen.setSerialNumber(new BigInteger("1"));
+
+ // not Before
+ acGen.setNotBefore(new Date(System.currentTimeMillis() - 50000));
+
+ // not After
+ acGen.setNotAfter(new Date(System.currentTimeMillis() + 50000));
+
+ // signature Algorithmus
+ acGen.setSignatureAlgorithm("SHA1WithRSAEncryption");
+
+ // Die eigentlichen Attribute
+ GeneralName roleName = new GeneralName(GeneralName.rfc822Name, "DAU123456789");
+ ASN1EncodableVector roleSyntax = new ASN1EncodableVector();
+ roleSyntax.add(roleName);
+
+ // roleSyntax OID: 2.5.24.72
+ X509Attribute attributes = new X509Attribute("2.5.24.72",
+ new DERSequence(roleSyntax));
+
+ acGen.addAttribute(attributes);
+
+ // Privaten Schluessel der CA lesen
+
+ // Und noch signieren
+ X509V2AttributeCertificate att = (X509V2AttributeCertificate)acGen
+ .generateCertificate(caPrivKey, "SC");
+
+ // Hier ist das Attributzertifikat fertig im Speicher, jetzt testen:
+
+ // Holder
+
+ AttributeCertificateHolder h = att.getHolder();
+ if (h.match(clientCert))
+ {
+ System.out.println("Matches original client x509 cert");
+ }
+
+ // Issuer
+
+ AttributeCertificateIssuer issuer = att.getIssuer();
+ if (issuer.match(caCert))
+ {
+ System.out.println("Matches original ca x509 cert");
+ }
+
+ // Dates
+ System.out.println("valid not before: " + att.getNotBefore());
+ System.out.println("valid not before: " + att.getNotAfter());
+
+ // Dates checken (bc wirft NotValid Exception wenn nicht g�ltig)
+
+ try
+ {
+ att.checkValidity();
+ att.checkValidity(new Date());
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+
+ // verify
+
+ try
+ {
+ att.verify(caPubKey, "SC");
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+
+ // Attribute
+ X509Attribute[] attribs = att.getAttributes();
+ System.out.println("cert has " + attribs.length + " attributes:");
+ for (int i = 0; i < attribs.length; i++)
+ {
+ X509Attribute a = attribs[i];
+ System.out.println("OID: " + a.getOID());
+ if (a.getOID().equals("2.5.24.72"))
+ {
+ System.out.println("rolesyntax read from cert!");
+ }
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
new file mode 100644
index 000000000..977725807
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
@@ -0,0 +1,397 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.sec.ECPrivateKeyStructure;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class BCECPrivateKey
+ implements ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ private String algorithm = "EC";
+ private boolean withCompression;
+
+ private transient BigInteger d;
+ private transient ECParameterSpec ecSpec;
+ private transient ProviderConfiguration configuration;
+ private transient DERBitString publicKey;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCECPrivateKey()
+ {
+ }
+
+ BCECPrivateKey(
+ ECPrivateKey key,
+ ProviderConfiguration configuration)
+ {
+ this.d = key.getD();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParameters();
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getD();
+ this.ecSpec = spec.getParams();
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECPublicKey pubKey,
+ ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.configuration = configuration;
+
+ if (spec == null)
+ {
+ this.ecSpec = new ECParameterSpec(
+ dp.getCurve(),
+ dp.getG(),
+ dp.getN(),
+ dp.getH(),
+ dp.getSeed());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ BCECPrivateKey key)
+ {
+ this.algorithm = algorithm;
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.publicKey = key.publicKey;
+ this.attrCarrier = key.attrCarrier;
+ this.configuration = key.configuration;
+ }
+
+ BCECPrivateKey(
+ PrivateKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.configuration = configuration;
+
+ populateFromPrivKeyInfo(info);
+ }
+
+ BCECPrivateKey(
+ String algorithm,
+ PrivateKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.configuration = configuration;
+ populateFromPrivKeyInfo(info);
+ this.algorithm = algorithm;
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ ecSpec = new ECNamedCurveParameterSpec(
+ ECUtil.getCurveName(oid),
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ ecSpec = new ECParameterSpec(ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+
+ if (info.getPrivateKey() instanceof ASN1Integer)
+ {
+ ASN1Integer derD = ASN1Integer.getInstance(info.getPrivateKey());
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)info.getPrivateKey());
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ X962Parameters params = null;
+
+ if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName());
+
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+ ECCurve curve = p.getG().getCurve();
+ ECPoint generator;
+
+ if (curve instanceof ECCurve.Fp)
+ {
+ generator = new ECPoint.Fp(curve, p.getG().getX(), p.getG().getY(), withCompression);
+ }
+ else if (curve instanceof ECCurve.F2m)
+ {
+ generator = new ECPoint.F2m(curve, p.getG().getX(), p.getG().getY(), withCompression);
+ }
+ else
+ {
+ throw new UnsupportedOperationException("Subclass of ECPoint " + curve.getClass().toString() + "not supported");
+ }
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(),
+ generator,
+ p.getN(),
+ p.getH(),
+ p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ ECPrivateKeyStructure keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getD(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getD(), params);
+ }
+
+ try
+ {
+ if (algorithm.equals("ECGOST3410"))
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), keyStructure);
+ }
+ else
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure);
+ }
+
+ return KeyUtil.getEncodedPrivateKeyInfo(info);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public ECParameterSpec getParameters()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return ecSpec;
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECPrivateKey))
+ {
+ return false;
+ }
+
+ BCECPrivateKey other = (BCECPrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private DERBitString getPublicKeyDetails(BCECPublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
new file mode 100644
index 000000000..9b93da86d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
@@ -0,0 +1,376 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ECPoint;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class BCECPublicKey
+ implements ECPublicKey, ECPointEncoder
+{
+ private String algorithm = "EC";
+ private boolean withCompression;
+
+ private transient org.spongycastle.math.ec.ECPoint q;
+ private transient ECParameterSpec ecSpec;
+ private transient ProviderConfiguration configuration;
+
+ public BCECPublicKey(
+ String algorithm,
+ BCECPublicKey key
+ )
+ {
+ this.algorithm = algorithm;
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.configuration = key.configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = spec.getQ();
+ this.configuration = configuration;
+
+ if (spec.getParams() != null)
+ {
+ this.ecSpec = spec.getParams();
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.spongycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+ }
+ this.ecSpec = null;
+ }
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.configuration = configuration;
+
+ if (spec == null)
+ {
+ this.ecSpec = new ECParameterSpec(
+ dp.getCurve(),
+ dp.getG(),
+ dp.getN(),
+ dp.getH(),
+ dp.getSeed());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ this.configuration = configuration;
+ }
+
+ BCECPublicKey(
+ ECPublicKey key,
+ ProviderConfiguration configuration)
+ {
+ this.q = key.getQ();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParameters();
+ this.configuration = configuration;
+ }
+
+ BCECPublicKey(
+ String algorithm,
+ ECPoint q,
+ ECParameterSpec ecSpec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = q;
+ this.ecSpec = ecSpec;
+ this.configuration = configuration;
+ }
+
+ BCECPublicKey(
+ SubjectPublicKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.configuration = configuration;
+
+ populateFromPubKeyInfo(info);
+ }
+
+ BCECPublicKey(
+ String algorithm,
+ SubjectPublicKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.configuration = configuration;
+ populateFromPubKeyInfo(info);
+ this.algorithm = algorithm;
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ ECCurve curve;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ ecSpec = new ECNamedCurveParameterSpec(
+ ECUtil.getCurveName(oid),
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ curve = ((ECParameterSpec)ecSpec).getCurve();
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ curve = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve();
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ ecSpec = new ECParameterSpec(
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ curve = ((ECParameterSpec)ecSpec).getCurve();
+ }
+
+ DERBitString bits = info.getPublicKeyData();
+ byte[] data = bits.getBytes();
+ ASN1OctetString key = new DEROctetString(data);
+
+ //
+ // extra octet string - one of our old certs...
+ //
+ if (data[0] == 0x04 && data[1] == data.length - 2
+ && (data[2] == 0x02 || data[2] == 0x03))
+ {
+ int qLength = new X9IntegerConverter().getByteLength(curve);
+
+ if (qLength >= data.length - 3)
+ {
+ try
+ {
+ key = (ASN1OctetString)ASN1Primitive.fromByteArray(data);
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+ }
+
+ X9ECPoint derQ = new X9ECPoint(curve, key);
+
+ this.q = derQ.getPoint();
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ SubjectPublicKeyInfo info;
+
+ X962Parameters params = null;
+ if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName());
+
+ if (curveOid == null)
+ {
+ curveOid = new DERObjectIdentifier(((ECNamedCurveParameterSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+
+ ECCurve curve = p.getG().getCurve();
+ ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression);
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(), generator, p.getN(), p.getH(), p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECCurve curve = this.engineGetQ().getCurve();
+ ECPoint point = curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression);
+ ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point));
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public ECParameterSpec getParameters()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public org.spongycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.spongycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.spongycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+ }
+ else
+ {
+ return new org.spongycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+ }
+ }
+
+ return q;
+ }
+
+ public org.spongycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.getQ().getX().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.getQ().getY().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECPublicKey))
+ {
+ return false;
+ }
+
+ BCECPublicKey other = (BCECPublicKey)o;
+
+ return getQ().equals(other.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
new file mode 100644
index 000000000..e1cd11b96
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -0,0 +1,317 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.crypto.BasicAgreement;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DerivationFunction;
+import org.spongycastle.crypto.agreement.ECDHBasicAgreement;
+import org.spongycastle.crypto.agreement.ECDHCBasicAgreement;
+import org.spongycastle.crypto.agreement.ECMQVBasicAgreement;
+import org.spongycastle.crypto.agreement.kdf.DHKDFParameters;
+import org.spongycastle.crypto.agreement.kdf.ECDHKEKGenerator;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.crypto.params.MQVPrivateParameters;
+import org.spongycastle.crypto.params.MQVPublicParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.MQVPrivateKey;
+import org.spongycastle.jce.interfaces.MQVPublicKey;
+import org.spongycastle.util.Integers;
+
+/**
+ * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+ * both the simple one, and the simple one with cofactors are supported.
+ *
+ * Also, MQV key agreement per SEC-1
+ */
+public class KeyAgreementSpi
+ extends javax.crypto.KeyAgreementSpi
+{
+ private static final X9IntegerConverter converter = new X9IntegerConverter();
+ private static final Hashtable algorithms = new Hashtable();
+
+ static
+ {
+ Integer i128 = Integers.valueOf(128);
+ Integer i192 = Integers.valueOf(192);
+ Integer i256 = Integers.valueOf(256);
+
+ algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
+ algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
+ algorithms.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
+ algorithms.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
+ algorithms.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
+ algorithms.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
+ algorithms.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
+ }
+
+ private String kaAlgorithm;
+ private BigInteger result;
+ private ECDomainParameters parameters;
+ private BasicAgreement agreement;
+ private DerivationFunction kdf;
+
+ private byte[] bigIntToBytes(
+ BigInteger r)
+ {
+ return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX()));
+ }
+
+ protected KeyAgreementSpi(
+ String kaAlgorithm,
+ BasicAgreement agreement,
+ DerivationFunction kdf)
+ {
+ this.kaAlgorithm = kaAlgorithm;
+ this.agreement = agreement;
+ this.kdf = kdf;
+ }
+
+ protected Key engineDoPhase(
+ Key key,
+ boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ if (parameters == null)
+ {
+ throw new IllegalStateException(kaAlgorithm + " not initialised.");
+ }
+
+ if (!lastPhase)
+ {
+ throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
+ }
+
+ CipherParameters pubKey;
+ if (agreement instanceof ECMQVBasicAgreement)
+ {
+ if (!(key instanceof MQVPublicKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(MQVPublicKey.class) + " for doPhase");
+ }
+
+ MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+ ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+ ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+
+ pubKey = new MQVPublicParameters(staticKey, ephemKey);
+
+ // TODO Validate that all the keys are using the same parameters?
+ }
+ else
+ {
+ if (!(key instanceof ECPublicKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPublicKey.class) + " for doPhase");
+ }
+
+ pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key);
+
+ // TODO Validate that all the keys are using the same parameters?
+ }
+
+ result = agreement.calculateAgreement(pubKey);
+
+ return null;
+ }
+
+ protected byte[] engineGenerateSecret()
+ throws IllegalStateException
+ {
+ if (kdf != null)
+ {
+ throw new UnsupportedOperationException(
+ "KDF can only be used when algorithm is known");
+ }
+
+ return bigIntToBytes(result);
+ }
+
+ protected int engineGenerateSecret(
+ byte[] sharedSecret,
+ int offset)
+ throws IllegalStateException, ShortBufferException
+ {
+ byte[] secret = engineGenerateSecret();
+
+ if (sharedSecret.length - offset < secret.length)
+ {
+ throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
+ }
+
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+
+ return secret.length;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ byte[] secret = bigIntToBytes(result);
+
+ if (kdf != null)
+ {
+ if (!algorithms.containsKey(algorithm))
+ {
+ throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
+ }
+
+ int keySize = ((Integer)algorithms.get(algorithm)).intValue();
+
+ DHKDFParameters params = new DHKDFParameters(new DERObjectIdentifier(algorithm), keySize, secret);
+
+ byte[] keyBytes = new byte[keySize / 8];
+ kdf.init(params);
+ kdf.generateBytes(keyBytes, 0, keyBytes.length);
+ secret = keyBytes;
+ }
+ else
+ {
+ // TODO Should we be ensuring the key is the right length?
+ }
+
+ return new SecretKeySpec(secret, algorithm);
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initFromKey(key);
+ }
+
+ protected void engineInit(
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ initFromKey(key);
+ }
+
+ private void initFromKey(Key key)
+ throws InvalidKeyException
+ {
+ if (agreement instanceof ECMQVBasicAgreement)
+ {
+ if (!(key instanceof MQVPrivateKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(MQVPrivateKey.class) + " for initialisation");
+ }
+
+ MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+ ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
+ ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+ ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
+ ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+
+ ECPublicKeyParameters ephemPubKey = null;
+ if (mqvPrivKey.getEphemeralPublicKey() != null)
+ {
+ ephemPubKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+ }
+
+ MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+ this.parameters = staticPrivKey.getParameters();
+
+ // TODO Validate that all the keys are using the same parameters?
+
+ agreement.init(localParams);
+ }
+ else
+ {
+ if (!(key instanceof ECPrivateKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPrivateKey.class) + " for initialisation");
+ }
+
+ ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+ this.parameters = privKey.getParameters();
+
+ agreement.init(privKey);
+ }
+ }
+
+ private static String getSimpleName(Class clazz)
+ {
+ String fullName = clazz.getName();
+
+ return fullName.substring(fullName.lastIndexOf('.') + 1);
+ }
+
+ public static class DH
+ extends KeyAgreementSpi
+ {
+ public DH()
+ {
+ super("ECDH", new ECDHBasicAgreement(), null);
+ }
+ }
+
+ public static class DHC
+ extends KeyAgreementSpi
+ {
+ public DHC()
+ {
+ super("ECDHC", new ECDHCBasicAgreement(), null);
+ }
+ }
+
+ public static class MQV
+ extends KeyAgreementSpi
+ {
+ public MQV()
+ {
+ super("ECMQV", new ECMQVBasicAgreement(), null);
+ }
+ }
+
+ public static class DHwithSHA1KDF
+ extends KeyAgreementSpi
+ {
+ public DHwithSHA1KDF()
+ {
+ super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ }
+ }
+
+ public static class MQVwithSHA1KDF
+ extends KeyAgreementSpi
+ {
+ public MQVwithSHA1KDF()
+ {
+ super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
new file mode 100644
index 000000000..76c11e0b5
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
@@ -0,0 +1,200 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ String algorithm;
+ ProviderConfiguration configuration;
+
+ KeyFactorySpi(
+ String algorithm,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPublicKey)
+ {
+ return new BCECPublicKey((ECPublicKey)key, configuration);
+ }
+ else if (key instanceof ECPrivateKey)
+ {
+ return new BCECPrivateKey((ECPrivateKey)key, configuration);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(k.getQ(), k.getParameters());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(k.getQ(), implicitSpec);
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getD(), k.getParameters());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = configuration.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getD(), implicitSpec);
+ }
+ }
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPrivateKeySpec)
+ {
+ return new BCECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec, configuration);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ return new BCECPrivateKey(algorithm, keyInfo, configuration);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ return new BCECPublicKey(algorithm, keyInfo, configuration);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public static class EC
+ extends KeyFactorySpi
+ {
+ public EC()
+ {
+ super("EC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDSA
+ extends KeyFactorySpi
+ {
+ public ECDSA()
+ {
+ super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECGOST3410
+ extends KeyFactorySpi
+ {
+ public ECGOST3410()
+ {
+ super("ECGOST3410", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDH
+ extends KeyFactorySpi
+ {
+ public ECDH()
+ {
+ super("ECDH", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDHC
+ extends KeyFactorySpi
+ {
+ public ECDHC()
+ {
+ super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECMQV
+ extends KeyFactorySpi
+ {
+ public ECMQV()
+ {
+ super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..8d74dd598
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
@@ -0,0 +1,259 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.sec.SECNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.asn1.x9.X962NamedCurves;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.ECKeyPairGenerator;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECKeyGenerationParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.ECNamedCurveTable;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.util.Integers;
+
+public abstract class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ public KeyPairGeneratorSpi(String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ public static class EC
+ extends KeyPairGeneratorSpi
+ {
+ ECKeyGenerationParameters param;
+ ECKeyPairGenerator engine = new ECKeyPairGenerator();
+ ECParameterSpec ecParams = null;
+ int strength = 239;
+ int certainty = 50;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+ String algorithm;
+ ProviderConfiguration configuration;
+
+ static private Hashtable ecParameters;
+
+ static {
+ ecParameters = new Hashtable();
+
+ ecParameters.put(Integers.valueOf(192),
+ ECNamedCurveTable.getParameterSpec("prime192v1"));
+ ecParameters.put(Integers.valueOf(239),
+ ECNamedCurveTable.getParameterSpec("prime239v1"));
+ ecParameters.put(Integers.valueOf(256),
+ ECNamedCurveTable.getParameterSpec("prime256v1"));
+ }
+
+ public EC()
+ {
+ super("EC");
+ this.algorithm = "EC";
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ }
+
+ public EC(
+ String algorithm,
+ ProviderConfiguration configuration)
+ {
+ super(algorithm);
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ this.ecParams = (ECParameterSpec)ecParameters.get(Integers.valueOf(strength));
+
+ if (ecParams != null)
+ {
+ param = new ECKeyGenerationParameters(new ECDomainParameters(ecParams.getCurve(), ecParams.getG(), ecParams.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else
+ {
+ throw new InvalidParameterException("unknown key size.");
+ }
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)params;
+ this.ecParams = (ECParameterSpec)params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof ECNamedCurveGenParameterSpec)
+ {
+ String curveName;
+
+ curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+
+ X9ECParameters ecP = X962NamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ ecP = SECNamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ ecP = NISTNamedCurves.getByName(curveName);
+ }
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.getByName(curveName);
+ }
+ if (ecP == null)
+ {
+ // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
+ try
+ {
+ ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName);
+ ecP = X962NamedCurves.getByOID(oid);
+ if (ecP == null)
+ {
+ ecP = SECNamedCurves.getByOID(oid);
+ }
+ if (ecP == null)
+ {
+ ecP = NISTNamedCurves.getByOID(oid);
+ }
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.getByOID(oid);
+ }
+ if (ecP == null)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+ }
+ }
+ }
+
+ this.ecParams = new ECNamedCurveParameterSpec(
+ curveName,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ null); // ecP.getSeed()); Work-around JDK bug -- it won't look up named curves properly if seed is present
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(ecParams.getCurve(), ecParams.getG(), ecParams.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && configuration.getEcImplicitlyCa() != null)
+ {
+ ECParameterSpec p = configuration.getEcImplicitlyCa();
+ this.ecParams = (ECParameterSpec)params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && configuration.getEcImplicitlyCa() == null)
+ {
+ throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException("EC Key Pair Generator not initialised");
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ if (ecParams == null)
+ {
+ return new KeyPair(new BCECPublicKey(algorithm, pub, configuration),
+ new BCECPrivateKey(algorithm, priv, configuration));
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecParams;
+ BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
+
+ return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
+ }
+ }
+ }
+
+ public static class ECDSA
+ extends EC
+ {
+ public ECDSA()
+ {
+ super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDH
+ extends EC
+ {
+ public ECDH()
+ {
+ super("ECDH", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDHC
+ extends EC
+ {
+ public ECDHC()
+ {
+ super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECMQV
+ extends EC
+ {
+ public ECMQV()
+ {
+ super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
new file mode 100644
index 000000000..6119af8bf
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -0,0 +1,355 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.NullDigest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.ECDSASigner;
+import org.spongycastle.crypto.signers.ECNRSigner;
+import org.spongycastle.jcajce.provider.asymmetric.util.DSABase;
+import org.spongycastle.jcajce.provider.asymmetric.util.DSAEncoder;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class SignatureSpi
+ extends DSABase
+{
+ SignatureSpi(Digest digest, DSA signer, DSAEncoder encoder)
+ {
+ super("ECDSA", digest, signer, encoder);
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+ }
+
+ digest.reset();
+
+ signer.init(false, param);
+ }
+
+ protected void doEngineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+
+ digest.reset();
+
+ if (random != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, random));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ static public class ecDSA
+ extends SignatureSpi
+ {
+ public ecDSA()
+ {
+ super(new SHA1Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSAnone
+ extends SignatureSpi
+ {
+ public ecDSAnone()
+ {
+ super(new NullDigest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA224
+ extends SignatureSpi
+ {
+ public ecDSA224()
+ {
+ super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA256
+ extends SignatureSpi
+ {
+ public ecDSA256()
+ {
+ super(new SHA256Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA384
+ extends SignatureSpi
+ {
+ public ecDSA384()
+ {
+ super(new SHA384Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA512
+ extends SignatureSpi
+ {
+ public ecDSA512()
+ {
+ super(new SHA512Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSARipeMD160
+ extends SignatureSpi
+ {
+ public ecDSARipeMD160()
+ {
+ super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR
+ extends SignatureSpi
+ {
+ public ecNR()
+ {
+ super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR224
+ extends SignatureSpi
+ {
+ public ecNR224()
+ {
+ super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR256
+ extends SignatureSpi
+ {
+ public ecNR256()
+ {
+ super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR384
+ extends SignatureSpi
+ {
+ public ecNR384()
+ {
+ super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR512
+ extends SignatureSpi
+ {
+ public ecNR512()
+ {
+ super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA
+ extends SignatureSpi
+ {
+ public ecCVCDSA()
+ {
+ super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA224
+ extends SignatureSpi
+ {
+ public ecCVCDSA224()
+ {
+ super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA256
+ extends SignatureSpi
+ {
+ public ecCVCDSA256()
+ {
+ super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA384
+ extends SignatureSpi
+ {
+ public ecCVCDSA384()
+ {
+ super(new SHA384Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA512
+ extends SignatureSpi
+ {
+ public ecCVCDSA512()
+ {
+ super(new SHA512Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ private static class StdDSAEncoder
+ implements DSAEncoder
+ {
+ public byte[] encode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DERInteger(r));
+ v.add(new DERInteger(s));
+
+ return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+ }
+
+ public BigInteger[] decode(
+ byte[] encoding)
+ throws IOException
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ BigInteger[] sig = new BigInteger[2];
+
+ sig[0] = ((DERInteger)s.getObjectAt(0)).getValue();
+ sig[1] = ((DERInteger)s.getObjectAt(1)).getValue();
+
+ return sig;
+ }
+ }
+
+ private static class CVCDSAEncoder
+ implements DSAEncoder
+ {
+ public byte[] encode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ byte[] first = makeUnsigned(r);
+ byte[] second = makeUnsigned(s);
+ byte[] res;
+
+ if (first.length > second.length)
+ {
+ res = new byte[first.length * 2];
+ }
+ else
+ {
+ res = new byte[second.length * 2];
+ }
+
+ System.arraycopy(first, 0, res, res.length / 2 - first.length, first.length);
+ System.arraycopy(second, 0, res, res.length - second.length, second.length);
+
+ return res;
+ }
+
+
+ private byte[] makeUnsigned(BigInteger val)
+ {
+ byte[] res = val.toByteArray();
+
+ if (res[0] == 0)
+ {
+ byte[] tmp = new byte[res.length - 1];
+
+ System.arraycopy(res, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return res;
+ }
+
+ public BigInteger[] decode(
+ byte[] encoding)
+ throws IOException
+ {
+ BigInteger[] sig = new BigInteger[2];
+
+ byte[] first = new byte[encoding.length / 2];
+ byte[] second = new byte[encoding.length / 2];
+
+ System.arraycopy(encoding, 0, first, 0, first.length);
+ System.arraycopy(encoding, first.length, second, 0, second.length);
+
+ sig[0] = new BigInteger(1, first);
+ sig[1] = new BigInteger(1, second);
+
+ return sig;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
new file mode 100644
index 000000000..43720d247
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
@@ -0,0 +1,371 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.sec.ECPrivateKeyStructure;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class BCECGOST3410PrivateKey
+ implements ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ private String algorithm = "ECGOST3410";
+ private boolean withCompression;
+
+ private transient BigInteger d;
+ private transient ECParameterSpec ecSpec;
+ private transient DERBitString publicKey;
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCECGOST3410PrivateKey()
+ {
+ }
+
+ BCECGOST3410PrivateKey(
+ ECPrivateKey key)
+ {
+ this.d = key.getD();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParameters();
+ }
+
+ public BCECGOST3410PrivateKey(
+ ECPrivateKeySpec spec)
+ {
+ this.d = spec.getD();
+ this.ecSpec = spec.getParams();
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECGOST3410PublicKey pubKey,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ this.ecSpec = new ECParameterSpec(
+ dp.getCurve(),
+ dp.getG(),
+ dp.getN(),
+ dp.getH(),
+ dp.getSeed());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ BCECGOST3410PrivateKey key)
+ {
+ this.algorithm = algorithm;
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.publicKey = key.publicKey;
+ this.attrCarrier = key.attrCarrier;
+ }
+
+ BCECGOST3410PrivateKey(
+ PrivateKeyInfo info)
+ {
+ populateFromPrivKeyInfo(info);
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+ ECDomainParameters ecP = ECGOST3410NamedCurves.getByOID(oid);
+
+ ecSpec = new ECNamedCurveParameterSpec(
+ ECUtil.getCurveName(oid),
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ ecSpec = new ECParameterSpec(ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+
+ if (info.getPrivateKey() instanceof ASN1Integer)
+ {
+ ASN1Integer derD = ASN1Integer.getInstance(info.getPrivateKey());
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)info.getPrivateKey());
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ X962Parameters params = null;
+
+ if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName());
+
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+ ECCurve curve = p.getG().getCurve();
+ ECPoint generator;
+
+ if (curve instanceof ECCurve.Fp)
+ {
+ generator = new ECPoint.Fp(curve, p.getG().getX(), p.getG().getY(), withCompression);
+ }
+ else if (curve instanceof ECCurve.F2m)
+ {
+ generator = new ECPoint.F2m(curve, p.getG().getX(), p.getG().getY(), withCompression);
+ }
+ else
+ {
+ throw new UnsupportedOperationException("Subclass of ECPoint " + curve.getClass().toString() + "not supported");
+ }
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(),
+ generator,
+ p.getN(),
+ p.getH(),
+ p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ ECPrivateKeyStructure keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getD(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getD(), params);
+ }
+
+ try
+ {
+ if (algorithm.equals("ECGOST3410"))
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), keyStructure);
+ }
+ else
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure);
+ }
+
+ return KeyUtil.getEncodedPrivateKeyInfo(info);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public ECParameterSpec getParameters()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return ecSpec;
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECGOST3410PrivateKey))
+ {
+ return false;
+ }
+
+ BCECGOST3410PrivateKey other = (BCECGOST3410PrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private DERBitString getPublicKeyDetails(BCECGOST3410PublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
new file mode 100644
index 000000000..2256bfd18
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
@@ -0,0 +1,454 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ECPoint;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class BCECGOST3410PublicKey
+ implements ECPublicKey, ECPointEncoder
+{
+ private String algorithm = "ECGOST3410";
+ private boolean withCompression;
+
+ private transient org.spongycastle.math.ec.ECPoint q;
+ private transient ECParameterSpec ecSpec;
+ private transient GOST3410PublicKeyAlgParameters gostParams;
+
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ BCECGOST3410PublicKey key)
+ {
+ this.algorithm = algorithm;
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.gostParams = key.gostParams;
+ }
+
+ public BCECGOST3410PublicKey(
+ ECPublicKeySpec spec)
+ {
+ this.q = spec.getQ();
+
+ if (spec.getParams() != null)
+ {
+ this.ecSpec = spec.getParams();
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.spongycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+ }
+ this.ecSpec = null;
+ }
+ }
+
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ this.ecSpec = new ECParameterSpec(
+ dp.getCurve(),
+ dp.getG(),
+ dp.getN(),
+ dp.getH(),
+ dp.getSeed());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+ }
+
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ }
+
+ BCECGOST3410PublicKey(
+ ECPublicKey key)
+ {
+ this.q = key.getQ();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParameters();
+ }
+
+ BCECGOST3410PublicKey(
+ String algorithm,
+ ECPoint q,
+ ECParameterSpec ecSpec)
+ {
+ this.algorithm = algorithm;
+ this.q = q;
+ this.ecSpec = ecSpec;
+ }
+
+ BCECGOST3410PublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ populateFromPubKeyInfo(info);
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ DERBitString bits = info.getPublicKeyData();
+ ASN1OctetString key;
+ this.algorithm = "ECGOST3410";
+
+ try
+ {
+ key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes());
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+
+ byte[] keyEnc = key.getOctets();
+ byte[] x = new byte[32];
+ byte[] y = new byte[32];
+
+ for (int i = 0; i != x.length; i++)
+ {
+ x[i] = keyEnc[32 - 1 - i];
+ }
+
+ for (int i = 0; i != y.length; i++)
+ {
+ y[i] = keyEnc[64 - 1 - i];
+ }
+
+ gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+
+ ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+
+ ecSpec = spec;
+
+ this.q = spec.getCurve().createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
+ }
+ else
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ ECCurve curve;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ ecSpec = new ECNamedCurveParameterSpec(
+ ECUtil.getCurveName(oid),
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ curve = ((ECParameterSpec)ecSpec).getCurve();
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ curve = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve();
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ ecSpec = new ECParameterSpec(
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ curve = ((ECParameterSpec)ecSpec).getCurve();
+ }
+
+ DERBitString bits = info.getPublicKeyData();
+ byte[] data = bits.getBytes();
+ ASN1OctetString key = new DEROctetString(data);
+
+ //
+ // extra octet string - one of our old certs...
+ //
+ if (data[0] == 0x04 && data[1] == data.length - 2
+ && (data[2] == 0x02 || data[2] == 0x03))
+ {
+ int qLength = new X9IntegerConverter().getByteLength(curve);
+
+ if (qLength >= data.length - 3)
+ {
+ try
+ {
+ key = (ASN1OctetString)ASN1Primitive.fromByteArray(data);
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+ }
+
+ X9ECPoint derQ = new X9ECPoint(curve, key);
+
+ this.q = derQ.getPoint();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ SubjectPublicKeyInfo info;
+
+ if (algorithm.equals("ECGOST3410"))
+ {
+ ASN1Encodable params = null;
+ if (gostParams != null)
+ {
+ params = gostParams;
+ }
+ else if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ params = new GOST3410PublicKeyAlgParameters(
+ ECGOST3410NamedCurves.getOID(((ECNamedCurveParameterSpec)ecSpec).getName()),
+ CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+
+ ECCurve curve = p.getG().getCurve();
+ ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression);
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(), generator, p.getN(), p.getH(), p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECPoint qq = this.getQ();
+ ECPoint point = qq.getCurve().createPoint(qq.getX().toBigInteger(), qq.getY().toBigInteger(), false);
+ ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point));
+
+ BigInteger bX = this.q.getX().toBigInteger();
+ BigInteger bY = this.q.getY().toBigInteger();
+ byte[] encKey = new byte[64];
+
+ byte[] val = bX.toByteArray();
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[i] = val[val.length - 1 - i];
+ }
+
+ val = bY.toByteArray();
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[32 + i] = val[val.length - 1 - i];
+ }
+
+ try
+ {
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ X962Parameters params = null;
+ if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName());
+
+ if (curveOid == null)
+ {
+ curveOid = new DERObjectIdentifier(((ECNamedCurveParameterSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+
+ ECCurve curve = p.getG().getCurve();
+ ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression);
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(), generator, p.getN(), p.getH(), p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECCurve curve = this.engineGetQ().getCurve();
+ ECPoint point = curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression);
+ ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point));
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public ECParameterSpec getParameters()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public org.spongycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.spongycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.spongycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+ }
+ else
+ {
+ return new org.spongycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+ }
+ }
+
+ return q;
+ }
+
+ public org.spongycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.getQ().getX().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.getQ().getY().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECGOST3410PublicKey))
+ {
+ return false;
+ }
+
+ BCECGOST3410PublicKey other = (BCECGOST3410PublicKey)o;
+
+ return getQ().equals(other.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
new file mode 100644
index 000000000..36847af27
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
@@ -0,0 +1,128 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(k.getQ(), k.getParameters());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(k.getQ(), implicitSpec);
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getD(), k.getParameters());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getD(), implicitSpec);
+ }
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPrivateKeySpec)
+ {
+ return new BCECGOST3410PrivateKey((ECPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ return new BCECGOST3410PrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ return new BCECGOST3410PublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
new file mode 100644
index 000000000..f950260e3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
@@ -0,0 +1,144 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.ECKeyPairGenerator;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECKeyGenerationParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ ECParameterSpec ecParams = null;
+ ECKeyPairGenerator engine = new ECKeyPairGenerator();
+
+ String algorithm = "ECGOST3410";
+ ECKeyGenerationParameters param;
+ int strength = 239;
+ SecureRandom random = null;
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("ECGOST3410");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+
+ if (ecParams != null)
+ {
+ param = new ECKeyGenerationParameters(new ECDomainParameters(ecParams.getCurve(), ecParams.getG(), ecParams.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else
+ {
+ throw new InvalidParameterException("unknown key size.");
+ }
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)params;
+ this.ecParams = p;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof ECNamedCurveGenParameterSpec)
+ {
+ String curveName;
+
+ curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+
+ ECDomainParameters ecP = ECGOST3410NamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+ }
+
+ this.ecParams = new ECNamedCurveParameterSpec(
+ curveName,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(ecParams.getCurve(), ecParams.getG(), ecParams.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() != null)
+ {
+ ECParameterSpec p = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ this.ecParams = null;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() == null)
+ {
+ throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec: " + params.getClass().getName());
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException("EC Key Pair Generator not initialised");
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ if (ecParams == null)
+ {
+ return new KeyPair(new BCECGOST3410PublicKey(algorithm, pub),
+ new BCECGOST3410PrivateKey(algorithm, priv));
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecParams;
+
+ BCECGOST3410PublicKey pubKey = new BCECGOST3410PublicKey(algorithm, pub, p);
+ return new KeyPair(pubKey,
+ new BCECGOST3410PrivateKey(algorithm, priv, pubKey, p));
+ }
+ }
+}
+
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
new file mode 100644
index 000000000..c3660fb1a
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
@@ -0,0 +1,219 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.ECGOST3410Signer;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.GOST3410Key;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.util.GOST3410Util;
+
+public class SignatureSpi
+ extends java.security.Signature
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+
+ public SignatureSpi()
+ {
+ super("ECGOST3410");
+ this.digest = new GOST3411Digest();
+ this.signer = new ECGOST3410Signer();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else if (publicKey instanceof GOST3410Key)
+ {
+ param = GOST3410Util.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+ }
+
+ digest.reset();
+
+ if (appRandom != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, appRandom));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] sigBytes = new byte[64];
+ BigInteger[] sig = signer.generateSignature(hash);
+ byte[] r = sig[0].toByteArray();
+ byte[] s = sig[1].toByteArray();
+
+ if (s[0] != 0)
+ {
+ System.arraycopy(s, 0, sigBytes, 32 - s.length, s.length);
+ }
+ else
+ {
+ System.arraycopy(s, 1, sigBytes, 32 - (s.length - 1), s.length - 1);
+ }
+
+ if (r[0] != 0)
+ {
+ System.arraycopy(r, 0, sigBytes, 64 - r.length, r.length);
+ }
+ else
+ {
+ System.arraycopy(r, 1, sigBytes, 64 - (r.length - 1), r.length - 1);
+ }
+
+ return sigBytes;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ byte[] r = new byte[32];
+ byte[] s = new byte[32];
+
+ System.arraycopy(sigBytes, 0, s, 0, 32);
+
+ System.arraycopy(sigBytes, 32, r, 0, 32);
+
+ sig = new BigInteger[2];
+ sig[0] = new BigInteger(1, r);
+ sig[1] = new BigInteger(1, s);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
new file mode 100644
index 000000000..7a6e69d3e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
@@ -0,0 +1,299 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.interfaces.DHKey;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.BufferedAsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.encodings.ISO9796d1Encoding;
+import org.spongycastle.crypto.encodings.OAEPEncoding;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.ElGamalEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.spongycastle.jce.interfaces.ElGamalKey;
+import org.spongycastle.jce.interfaces.ElGamalPrivateKey;
+import org.spongycastle.jce.interfaces.ElGamalPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class CipherSpi
+ extends BaseCipherSpi
+{
+ private BufferedAsymmetricBlockCipher cipher;
+ private AlgorithmParameterSpec paramSpec;
+ private AlgorithmParameters engineParams;
+
+ public CipherSpi(
+ AsymmetricBlockCipher engine)
+ {
+ cipher = new BufferedAsymmetricBlockCipher(engine);
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return cipher.getInputBlockSize();
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (key instanceof ElGamalKey)
+ {
+ ElGamalKey k = (ElGamalKey)key;
+
+ return k.getParameters().getP().bitLength();
+ }
+ else if (key instanceof DHKey)
+ {
+ DHKey k = (DHKey)key;
+
+ return k.getParams().getP().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an ElGamal key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return cipher.getOutputBlockSize();
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ String md = Strings.toUpperCase(mode);
+
+ if (md.equals("NONE") || md.equals("ECB"))
+ {
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String pad = Strings.toUpperCase(padding);
+
+ if (pad.equals("NOPADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new ElGamalEngine());
+ }
+ else if (pad.equals("PKCS1PADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new PKCS1Encoding(new ElGamalEngine()));
+ }
+ else if (pad.equals("ISO9796-1PADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new ISO9796d1Encoding(new ElGamalEngine()));
+ }
+ else if (pad.equals("OAEPPADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new OAEPEncoding(new ElGamalEngine()));
+ }
+ else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new OAEPEncoding(new ElGamalEngine()));
+ }
+ else
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with ElGamal.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (params == null)
+ {
+ if (key instanceof ElGamalPublicKey)
+ {
+ param = ElGamalUtil.generatePublicKeyParameter((PublicKey)key);
+ }
+ else if (key instanceof ElGamalPrivateKey)
+ {
+ param = ElGamalUtil.generatePrivateKeyParameter((PrivateKey)key);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown key type passed to ElGamal");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown parameter type.");
+ }
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ switch (opmode)
+ {
+ case javax.crypto.Cipher.ENCRYPT_MODE:
+ case javax.crypto.Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case javax.crypto.Cipher.DECRYPT_MODE:
+ case javax.crypto.Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed to ElGamal");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameters in ElGamal");
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ try
+ {
+ return cipher.doFinal();
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ byte[] out;
+
+ cipher.processBytes(input, inputOffset, inputLen);
+
+ try
+ {
+ out = cipher.doFinal();
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+
+ /**
+ * classes that inherit from us.
+ */
+ static public class NoPadding
+ extends CipherSpi
+ {
+ public NoPadding()
+ {
+ super(new ElGamalEngine());
+ }
+ }
+
+ static public class PKCS1v1_5Padding
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding()
+ {
+ super(new PKCS1Encoding(new ElGamalEngine()));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 000000000..eb66bcf36
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,217 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.PSSParameterSpec;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+
+public abstract class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class OAEP
+ extends AlgorithmParametersSpi
+ {
+ AlgorithmParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
+ */
+ protected byte[] engineGetEncoded()
+ {
+ return null;
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ this.currentSpec = paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+
+ throw new IOException("Operation not supported");
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "OAEP Parameters";
+ }
+ }
+
+ public static class PSS
+ extends AlgorithmParametersSpi
+ {
+ PSSParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+ */
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ PSSParameterSpec pssSpec = (PSSParameterSpec)currentSpec;
+ RSASSAPSSparams pssP = new RSASSAPSSparams(RSASSAPSSparams.DEFAULT_HASH_ALGORITHM, RSASSAPSSparams.DEFAULT_MASK_GEN_FUNCTION, new ASN1Integer(pssSpec.getSaltLength()), RSASSAPSSparams.DEFAULT_TRAILER_FIELD);
+
+ dOut.writeObject(pssP);
+ dOut.close();
+
+ return bOut.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PSSParameterSpec.class && currentSpec != null)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PSSParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
+ }
+
+ this.currentSpec = (PSSParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+ currentSpec = new PSSParameterSpec(
+ pssP.getSaltLength().intValue());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "PSS Parameters";
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
new file mode 100644
index 000000000..7609b4a74
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -0,0 +1,509 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+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.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.encodings.ISO9796d1Encoding;
+import org.spongycastle.crypto.encodings.OAEPEncoding;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class CipherSpi
+ extends BaseCipherSpi
+{
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmParameterSpec paramSpec;
+ private AlgorithmParameters engineParams;
+ private boolean publicKeyOnly = false;
+ private boolean privateKeyOnly = false;
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public CipherSpi(
+ AsymmetricBlockCipher engine)
+ {
+ cipher = engine;
+ }
+
+ public CipherSpi(
+ boolean publicKeyOnly,
+ boolean privateKeyOnly,
+ AsymmetricBlockCipher engine)
+ {
+ this.publicKeyOnly = publicKeyOnly;
+ this.privateKeyOnly = privateKeyOnly;
+ cipher = engine;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ try
+ {
+ return cipher.getInputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (key instanceof RSAPrivateKey)
+ {
+ RSAPrivateKey k = (RSAPrivateKey)key;
+
+ return k.getModulus().bitLength();
+ }
+ else if (key instanceof RSAPublicKey)
+ {
+ RSAPublicKey k = (RSAPublicKey)key;
+
+ return k.getModulus().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an RSA key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ try
+ {
+ return cipher.getOutputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ String md = Strings.toUpperCase(mode);
+
+ if (md.equals("NONE") || md.equals("ECB"))
+ {
+ return;
+ }
+
+ if (md.equals("1"))
+ {
+ privateKeyOnly = true;
+ publicKeyOnly = false;
+ return;
+ }
+ else if (md.equals("2"))
+ {
+ privateKeyOnly = false;
+ publicKeyOnly = true;
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String pad = Strings.toUpperCase(padding);
+
+ if (pad.equals("NOPADDING"))
+ {
+ cipher = new RSABlindedEngine();
+ }
+ else if (pad.equals("PKCS1PADDING"))
+ {
+ cipher = new PKCS1Encoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("ISO9796-1PADDING"))
+ {
+ cipher = new ISO9796d1Encoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("OAEPPADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new SHA224Digest());
+ }
+ else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new SHA256Digest());
+ }
+ else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new SHA384Digest());
+ }
+ else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new SHA512Digest());
+ }
+ else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new MD5Digest());
+ }
+ else
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (params == null)
+ {
+ if (key instanceof RSAPublicKey)
+ {
+ if (privateKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 1 requires RSAPrivateKey");
+ }
+
+ param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)key);
+ }
+ else if (key instanceof RSAPrivateKey)
+ {
+ if (publicKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 2 requires RSAPublicKey");
+ }
+
+ param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)key);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown key type passed to RSA");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown parameter type.");
+ }
+
+ if (!(cipher instanceof RSABlindedEngine))
+ {
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+ else
+ {
+ param = new ParametersWithRandom(param, new SecureRandom());
+ }
+ }
+
+ switch (opmode)
+ {
+ case javax.crypto.Cipher.ENCRYPT_MODE:
+ case javax.crypto.Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case javax.crypto.Cipher.DECRYPT_MODE:
+ case javax.crypto.Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed to RSA");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ throw new InvalidAlgorithmParameterException("cannot recognise parameters.");
+ }
+
+ engineParams = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // this shouldn't happen
+ throw new InvalidKeyException("Eeeek! " + e.toString());
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ byte[] out;
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+ bOut.reset();
+
+ out = cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+
+ /**
+ * classes that inherit from us.
+ */
+
+ static public class NoPadding
+ extends CipherSpi
+ {
+ public NoPadding()
+ {
+ super(new RSABlindedEngine());
+ }
+ }
+
+ static public class PKCS1v1_5Padding
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding()
+ {
+ super(new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class PKCS1v1_5Padding_PrivateOnly
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding_PrivateOnly()
+ {
+ super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class PKCS1v1_5Padding_PublicOnly
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding_PublicOnly()
+ {
+ super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class OAEPPadding
+ extends CipherSpi
+ {
+ public OAEPPadding()
+ {
+ super(new OAEPEncoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class ISO9796d1Padding
+ extends CipherSpi
+ {
+ public ISO9796d1Padding()
+ {
+ super(new ISO9796d1Encoding(new RSABlindedEngine()));
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
new file mode 100644
index 000000000..23dd01004
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
@@ -0,0 +1,405 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class PSSSignatureSpi
+ extends Signature
+{
+ private AlgorithmParameters engineParams;
+ private PSSParameterSpec paramSpec;
+ private AsymmetricBlockCipher signer;
+ private Digest contentDigest;
+ private Digest mgfDigest;
+ private int saltLength;
+ private byte trailer;
+ private boolean isRaw;
+
+ private org.spongycastle.crypto.signers.PSSSigner pss;
+
+ private byte getTrailer(
+ int trailerField)
+ {
+ if (trailerField == 1)
+ {
+ return org.spongycastle.crypto.signers.PSSSigner.TRAILER_IMPLICIT;
+ }
+
+ throw new IllegalArgumentException("unknown trailer field");
+ }
+
+ private void setupContentDigest()
+ {
+ if (isRaw)
+ {
+ this.contentDigest = new NullPssDigest(mgfDigest);
+ }
+ else
+ {
+ this.contentDigest = mgfDigest;
+ }
+ }
+
+ protected PSSSignatureSpi(
+ String name,
+ AsymmetricBlockCipher signer,
+ Digest digest)
+ {
+ super(name);
+
+ this.signer = signer;
+ this.mgfDigest = digest;
+
+ if (digest != null)
+ {
+ this.saltLength = digest.getDigestSize();
+ }
+ else
+ {
+ this.saltLength = 20;
+ }
+
+ if (paramSpec != null)
+ {
+ this.saltLength = paramSpec.getSaltLength();
+ }
+ this.isRaw = false;
+
+ setupContentDigest();
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected PSSSignatureSpi(
+ String name,
+ AsymmetricBlockCipher signer,
+ Digest digest,
+ boolean isRaw)
+ {
+ super(name);
+
+ this.signer = signer;
+ this.mgfDigest = digest;
+
+ if (digest != null)
+ {
+ this.saltLength = digest.getDigestSize();
+ }
+ else
+ {
+ this.saltLength = 20;
+ }
+
+ if (paramSpec != null)
+ {
+ this.saltLength = paramSpec.getSaltLength();
+ }
+
+ this.isRaw = isRaw;
+
+ setupContentDigest();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPublicKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(false,
+ RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey));
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(true, new ParametersWithRandom(RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey), random));
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(true, RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey));
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ pss.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ pss.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ return pss.generateSignature();
+ }
+ catch (CryptoException e)
+ {
+ throw new SignatureException(e.getMessage());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ return pss.verifySignature(sigBytes);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ throws InvalidParameterException
+ {
+ if (params instanceof PSSParameterSpec)
+ {
+ PSSParameterSpec newParamSpec = (PSSParameterSpec)params;
+
+ this.engineParams = null;
+ this.paramSpec = newParamSpec;
+ this.saltLength = paramSpec.getSaltLength();
+
+ if (mgfDigest == null)
+ {
+ switch (saltLength)
+ {
+ case 20:
+ this.mgfDigest = new SHA1Digest();
+ break;
+ case 28:
+ this.mgfDigest = new SHA224Digest();
+ break;
+ case 32:
+ this.mgfDigest = new SHA256Digest();
+ break;
+ case 48:
+ this.mgfDigest = new SHA384Digest();
+ break;
+ case 64:
+ this.mgfDigest = new SHA512Digest();
+ break;
+ }
+ setupContentDigest();
+ }
+ }
+ else
+ {
+ throw new InvalidParameterException("Only PSSParameterSpec supported");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("PSS", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(new PSSParameterSpec(saltLength));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ return engineParams;
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineGetParameter unsupported");
+ }
+
+ static public class nonePSS
+ extends PSSSignatureSpi
+ {
+ public nonePSS()
+ {
+ super("NONEwithRSAandMGF1", new RSABlindedEngine(), null, true);
+ }
+ }
+
+ static public class PSSwithRSA
+ extends PSSSignatureSpi
+ {
+ public PSSwithRSA()
+ {
+ super("SHA1withRSAandMGF1", new RSABlindedEngine(), null);
+ }
+ }
+
+ static public class SHA1withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA1withRSA()
+ {
+ super("SHA1withRSAandMGF1", new RSABlindedEngine(), new SHA1Digest());
+ }
+ }
+
+ static public class SHA224withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA224withRSA()
+ {
+ super("SHA224withRSAandMGF1", new RSABlindedEngine(), new SHA224Digest());
+ }
+ }
+
+ static public class SHA256withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA256withRSA()
+ {
+ super("SHA256withRSAandMGF1", new RSABlindedEngine(), new SHA256Digest());
+ }
+ }
+
+ static public class SHA384withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA384withRSA()
+ {
+ super("SHA384withRSAandMGF1", new RSABlindedEngine(), new SHA384Digest());
+ }
+ }
+
+ static public class SHA512withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA512withRSA()
+ {
+ super("SHA512withRSAandMGF1", new RSABlindedEngine(), new SHA512Digest());
+ }
+ }
+
+ private class NullPssDigest
+ implements Digest
+ {
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ private Digest baseDigest;
+ private boolean oddTime = true;
+
+ public NullPssDigest(Digest mgfDigest)
+ {
+ this.baseDigest = mgfDigest;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "NULL";
+ }
+
+ public int getDigestSize()
+ {
+ return baseDigest.getDigestSize();
+ }
+
+ public void update(byte in)
+ {
+ bOut.write(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ bOut.write(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ byte[] res = bOut.toByteArray();
+
+ if (oddTime)
+ {
+ System.arraycopy(res, 0, out, outOff, res.length);
+ }
+ else
+ {
+ baseDigest.update(res, 0, res.length);
+
+ baseDigest.doFinal(out, outOff);
+ }
+
+ reset();
+
+ oddTime = !oddTime;
+
+ return res.length;
+ }
+
+ public void reset()
+ {
+ bOut.reset();
+ baseDigest.reset();
+ }
+
+ public int getByteLength()
+ {
+ return 0;
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java
new file mode 100644
index 000000000..bdc65b044
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java
@@ -0,0 +1,128 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+
+public abstract class DSABase
+ extends Signature
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ protected Digest digest;
+ protected DSA signer;
+ protected DSAEncoder encoder;
+
+ protected DSABase(
+ String name,
+ Digest digest,
+ DSA signer,
+ DSAEncoder encoder)
+ {
+ super(name);
+
+ this.digest = digest;
+ this.signer = signer;
+ this.encoder = encoder;
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ doEngineInitSign(privateKey, appRandom);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+
+ return encoder.encode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ sig = encoder.decode(sigBytes);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ protected abstract void doEngineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException;
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java
new file mode 100644
index 000000000..8cfba71fa
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java
@@ -0,0 +1,220 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.sec.SECNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.asn1.x9.X962NamedCurves;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+/**
+ * utility class for converting jce/jca ECDSA, ECDH, and ECDHC
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class ECUtil
+{
+ /**
+ * Returns a sorted array of middle terms of the reduction polynomial.
+ * @param k The unsorted array of middle terms of the reduction polynomial
+ * of length 1 or 3.
+ * @return the sorted array of middle terms of the reduction polynomial.
+ * This array always has length 3.
+ */
+ static int[] convertMidTerms(
+ int[] k)
+ {
+ int[] res = new int[3];
+
+ if (k.length == 1)
+ {
+ res[0] = k[0];
+ }
+ else
+ {
+ if (k.length != 3)
+ {
+ throw new IllegalArgumentException("Only Trinomials and pentanomials supported");
+ }
+
+ if (k[0] < k[1] && k[0] < k[2])
+ {
+ res[0] = k[0];
+ if (k[1] < k[2])
+ {
+ res[1] = k[1];
+ res[2] = k[2];
+ }
+ else
+ {
+ res[1] = k[2];
+ res[2] = k[1];
+ }
+ }
+ else if (k[1] < k[2])
+ {
+ res[0] = k[1];
+ if (k[0] < k[2])
+ {
+ res[1] = k[0];
+ res[2] = k[2];
+ }
+ else
+ {
+ res[1] = k[2];
+ res[2] = k[0];
+ }
+ }
+ else
+ {
+ res[0] = k[2];
+ if (k[0] < k[1])
+ {
+ res[1] = k[0];
+ res[2] = k[1];
+ }
+ else
+ {
+ res[1] = k[1];
+ res[2] = k[0];
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public static AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ ECParameterSpec s = k.getParameters();
+
+ if (s == null)
+ {
+ s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new ECPublicKeyParameters(
+ ((BCECPublicKey)k).engineGetQ(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ else
+ {
+ return new ECPublicKeyParameters(
+ k.getQ(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ }
+
+ throw new InvalidKeyException("cannot identify EC public key.");
+ }
+
+ public static AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+ ECParameterSpec s = k.getParameters();
+
+ if (s == null)
+ {
+ s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ return new ECPrivateKeyParameters(
+ k.getD(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+
+ throw new InvalidKeyException("can't identify EC private key.");
+ }
+
+ public static ASN1ObjectIdentifier getNamedCurveOid(
+ String name)
+ {
+ ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name);
+
+ if (oid == null)
+ {
+ oid = SECNamedCurves.getOID(name);
+ if (oid == null)
+ {
+ oid = NISTNamedCurves.getOID(name);
+ }
+ if (oid == null)
+ {
+ oid = TeleTrusTNamedCurves.getOID(name);
+ }
+ if (oid == null)
+ {
+ oid = ECGOST3410NamedCurves.getOID(name);
+ }
+ }
+
+ return oid;
+ }
+
+ public static X9ECParameters getNamedCurveByOid(
+ ASN1ObjectIdentifier oid)
+ {
+ X9ECParameters params = X962NamedCurves.getByOID(oid);
+
+ if (params == null)
+ {
+ params = SECNamedCurves.getByOID(oid);
+ if (params == null)
+ {
+ params = NISTNamedCurves.getByOID(oid);
+ }
+ if (params == null)
+ {
+ params = TeleTrusTNamedCurves.getByOID(oid);
+ }
+ }
+
+ return params;
+ }
+
+ public static String getCurveName(
+ ASN1ObjectIdentifier oid)
+ {
+ String name = X962NamedCurves.getName(oid);
+
+ if (name == null)
+ {
+ name = SECNamedCurves.getName(oid);
+ if (name == null)
+ {
+ name = NISTNamedCurves.getName(oid);
+ }
+ if (name == null)
+ {
+ name = TeleTrusTNamedCurves.getName(oid);
+ }
+ if (name == null)
+ {
+ name = ECGOST3410NamedCurves.getName(oid);
+ }
+ }
+
+ return name;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
new file mode 100644
index 000000000..a3909fd99
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -0,0 +1,1624 @@
+package org.spongycastle.jcajce.provider.keystore.pkcs12;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.BEROutputStream;
+import org.spongycastle.asn1.DERBMPString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.AuthenticatedSafe;
+import org.spongycastle.asn1.pkcs.CertBag;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.EncryptedData;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PBES2Parameters;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.util.SecretKeyUtil;
+import org.spongycastle.jce.interfaces.BCKeyStore;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.encoders.Hex;
+
+public class PKCS12KeyStoreSpi
+ extends KeyStoreSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+ private static final int SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private static final Provider bcProvider = new BouncyCastleProvider();
+
+ private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private Hashtable localIds = new Hashtable();
+ private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private Hashtable chainCerts = new Hashtable();
+ private Hashtable keyCerts = new Hashtable();
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected SecureRandom random = new SecureRandom();
+
+ // use of final causes problems with JDK 1.2 compiler
+ private CertificateFactory certFact;
+ private ASN1ObjectIdentifier keyAlgorithm;
+ private ASN1ObjectIdentifier certAlgorithm;
+
+ private class CertId
+ {
+ byte[] id;
+
+ CertId(
+ PublicKey key)
+ {
+ this.id = createSubjectKeyId(key).getKeyIdentifier();
+ }
+
+ CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(id);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof CertId))
+ {
+ return false;
+ }
+
+ CertId cId = (CertId)o;
+
+ return Arrays.areEqual(id, cId.id);
+ }
+ }
+
+ public PKCS12KeyStoreSpi(
+ Provider provider,
+ ASN1ObjectIdentifier keyAlgorithm,
+ ASN1ObjectIdentifier certAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+
+ try
+ {
+ if (provider != null)
+ {
+ certFact = CertificateFactory.getInstance("X.509", provider);
+ }
+ else
+ {
+ certFact = CertificateFactory.getInstance("X.509");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+ }
+ }
+
+ private SubjectKeyIdentifier createSubjectKeyId(
+ PublicKey pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)ASN1Primitive.fromByteArray(pubKey.getEncoded()));
+
+ return new SubjectKeyIdentifier(info);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error creating key");
+ }
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (certs.get(alias) != null || keys.get(alias) != null);
+ }
+
+ /**
+ * this is not quite complete - we should follow up on the chain, a bit
+ * tricky if a certificate appears in more than one chain...
+ */
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Key k = (Key)keys.remove(alias);
+
+ Certificate c = (Certificate)certs.remove(alias);
+
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+
+ if (k != null)
+ {
+ String id = (String)localIds.remove(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.remove(id);
+ }
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+ }
+ }
+
+ /**
+ * simply return the cert for the private key
+ */
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificate.");
+ }
+
+ Certificate c = (Certificate)certs.get(alias);
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ String id = (String)localIds.get(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.get(id);
+ }
+ else
+ {
+ c = (Certificate)keyCerts.get(alias);
+ }
+ }
+
+ return c;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration c = certs.elements();
+ Enumeration k = certs.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ c = keyCerts.elements();
+ k = keyCerts.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+ }
+
+ if (!engineIsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ Certificate c = engineGetCertificate(alias);
+
+ if (c != null)
+ {
+ Vector cs = new Vector();
+
+ while (c != null)
+ {
+ X509Certificate x509c = (X509Certificate)c;
+ Certificate nextC = null;
+
+ byte[] bytes = x509c.getExtensionValue(Extension.authorityKeyIdentifier.getId());
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(bytes);
+
+ byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+ aIn = new ASN1InputStream(authBytes);
+
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject());
+ if (id.getKeyIdentifier() != null)
+ {
+ nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+ }
+
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ Principal i = x509c.getIssuerDN();
+ Principal s = x509c.getSubjectDN();
+
+ if (!i.equals(s))
+ {
+ Enumeration e = chainCerts.keys();
+
+ while (e.hasMoreElements())
+ {
+ X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+ Principal sub = crt.getSubjectDN();
+ if (sub.equals(i))
+ {
+ try
+ {
+ x509c.verify(crt.getPublicKey());
+ nextC = crt;
+ break;
+ }
+ catch (Exception ex)
+ {
+ // continue
+ }
+ }
+ }
+ }
+ }
+
+ cs.addElement(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ Certificate[] certChain = new Certificate[cs.size()];
+
+ for (int i = 0; i != certChain.length; i++)
+ {
+ certChain[i] = (Certificate)cs.elementAt(i);
+ }
+
+ return certChain;
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ if (alias == null)
+ {
+ throw new NullPointerException("alias == null");
+ }
+ if (keys.get(alias) == null && certs.get(alias) == null)
+ {
+ return null;
+ }
+ return new Date();
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getKey.");
+ }
+
+ return (Key)keys.get(alias);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ return (certs.get(alias) != null && keys.get(alias) == null);
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ return (keys.get(alias) != null);
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ if (keys.get(alias) != null)
+ {
+ throw new KeyStoreException("There is a key entry with the name " + alias + ".");
+ }
+
+ certs.put(alias, cert);
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ throw new RuntimeException("operation not supported");
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ if (!(key instanceof PrivateKey))
+ {
+ throw new KeyStoreException("PKCS12 does not support non-PrivateKeys");
+ }
+
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ if (keys.get(alias) != null)
+ {
+ engineDeleteEntry(alias);
+ }
+
+ keys.put(alias, key);
+ if (chain != null)
+ {
+ certs.put(alias, chain[0]);
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+ }
+ }
+ }
+
+ public int engineSize()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.size();
+ }
+
+ protected PrivateKey unwrapKey(
+ AlgorithmIdentifier algId,
+ byte[] data,
+ char[] password,
+ boolean wrongPKCS12Zero)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+ try
+ {
+ if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+ {
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PrivateKey out;
+
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ SecretKey k = keyFact.generateSecret(pbeSpec);
+
+ ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+ {
+ PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
+ PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
+
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider);
+
+ SecretKey k = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), SecretKeyUtil.getKeySize(alg.getEncryptionScheme().getAlgorithm())));
+
+ Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId(), bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, new IvParameterSpec(ASN1OctetString.getInstance(alg.getEncryptionScheme().getParameters()).getOctets()));
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception unwrapping private key - " + e.toString());
+ }
+
+ throw new IOException("exception unwrapping private key - cannot recognise: " + algorithm);
+ }
+
+ protected byte[] wrapKey(
+ String algorithm,
+ Key key,
+ PKCS12PBEParams pbeParams,
+ char[] password)
+ throws IOException
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ byte[] out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+ out = cipher.wrap(key);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception encrypting data - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] cryptData(
+ boolean forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ boolean wrongPKCS12Zero,
+ byte[] data)
+ throws IOException
+ {
+ String algorithm = algId.getAlgorithm().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+ BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+
+ key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+ int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+ cipher.init(mode, key, defParams);
+ return cipher.doFinal(data);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decrypting data - " + e.toString());
+ }
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+ bufIn.mark(10);
+
+ int head = bufIn.read();
+
+ if (head != 0x30)
+ {
+ throw new IOException("stream does not represent a PKCS12 key store");
+ }
+
+ bufIn.reset();
+
+ ASN1InputStream bIn = new ASN1InputStream(bufIn);
+ ASN1Sequence obj = (ASN1Sequence)bIn.readObject();
+ Pfx bag = Pfx.getInstance(obj);
+ ContentInfo info = bag.getAuthSafe();
+ Vector chain = new Vector();
+ boolean unmarkedKey = false;
+ boolean wrongPKCS12Zero = false;
+
+ if (bag.getMacData() != null) // check the mac code
+ {
+ MacData mData = bag.getMacData();
+ DigestInfo dInfo = mData.getMac();
+ AlgorithmIdentifier algId = dInfo.getAlgorithmId();
+ byte[] salt = mData.getSalt();
+ int itCount = mData.getIterationCount().intValue();
+
+ byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
+
+ try
+ {
+ byte[] res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, false, data);
+ byte[] dig = dInfo.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ if (password.length > 0)
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ // Try with incorrect zero length password
+ res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, true, data);
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ wrongPKCS12Zero = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+ }
+
+ keys = new IgnoresCaseHashtable();
+ localIds = new Hashtable();
+
+ if (info.getContentType().equals(data))
+ {
+ bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+ AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
+ ContentInfo[] c = authSafe.getContentInfo();
+
+ for (int i = 0; i != c.length; i++)
+ {
+ if (c[i].getContentType().equals(data))
+ {
+ ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+ if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ unmarkedKey = true;
+ keys.put("unmarked", privKey);
+ }
+ }
+ else if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else
+ {
+ System.out.println("extra in data " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else if (c[i].getContentType().equals(encryptedData))
+ {
+ EncryptedData d = EncryptedData.getInstance(c[i].getContent());
+ byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
+ password, wrongPKCS12Zero, d.getContent().getOctets());
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(octets);
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+ if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else if (b.getBagId().equals(keyBag))
+ {
+ org.spongycastle.asn1.pkcs.PrivateKeyInfo kInfo = org.spongycastle.asn1.pkcs.PrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ System.out.println("extra in encryptedData " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else
+ {
+ System.out.println("extra " + c[i].getContentType().getId());
+ System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+ }
+ }
+ }
+
+ certs = new IgnoresCaseHashtable();
+ chainCerts = new Hashtable();
+ keyCerts = new Hashtable();
+
+ for (int i = 0; i != chain.size(); i++)
+ {
+ SafeBag b = (SafeBag)chain.elementAt(i);
+ CertBag cb = CertBag.getInstance(b.getBagValue());
+
+ if (!cb.getCertId().equals(x509Certificate))
+ {
+ throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
+ }
+
+ Certificate cert;
+
+ try
+ {
+ ByteArrayInputStream cIn = new ByteArrayInputStream(
+ ((ASN1OctetString)cb.getCertValue()).getOctets());
+ cert = certFact.generateCertificate(cIn);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+
+ //
+ // set the attributes
+ //
+ ASN1OctetString localId = null;
+ String alias = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Primitive attr = (ASN1Primitive)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
+ PKCS12BagAttributeCarrier bagAttr = null;
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(oid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(oid, attr);
+ }
+ }
+
+ if (oid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ }
+ else if (oid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+ if (unmarkedKey)
+ {
+ if (keyCerts.isEmpty())
+ {
+ String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+
+ keyCerts.put(name, cert);
+ keys.put(name, keys.remove("unmarked"));
+ }
+ }
+ else
+ {
+ //
+ // the local key id needs to override the friendly name
+ //
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ keyCerts.put(name, cert);
+ }
+ if (alias != null)
+ {
+ certs.put(alias, cert);
+ }
+ }
+ }
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ doStore(stream, password, false);
+ }
+
+ private void doStore(OutputStream stream, char[] password, boolean useDEREncoding)
+ throws IOException
+ {
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ //
+ // handle the key
+ //
+ ASN1EncodableVector keyS = new ASN1EncodableVector();
+
+
+ Enumeration ks = keys.keys();
+
+ while (ks.hasMoreElements())
+ {
+ byte[] kSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(kSalt);
+
+ String name = (String)ks.nextElement();
+ PrivateKey privKey = (PrivateKey)keys.get(name);
+ PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+ byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+ AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+ boolean attrSet = false;
+ ASN1EncodableVector kName = new ASN1EncodableVector();
+
+ if (privKey instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ Certificate ct = engineGetCertificate(name);
+
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+
+ kSeq.add(oid);
+ kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+ attrSet = true;
+
+ kName.add(new DERSequence(kSeq));
+ }
+ }
+
+ if (!attrSet)
+ {
+ //
+ // set a default friendly name (from the key id) and local id
+ //
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+ Certificate ct = engineGetCertificate(name);
+
+ kSeq.add(pkcs_9_at_localKeyId);
+ kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+ kName.add(new DERSequence(kSeq));
+
+ kSeq = new ASN1EncodableVector();
+
+ kSeq.add(pkcs_9_at_friendlyName);
+ kSeq.add(new DERSet(new DERBMPString(name)));
+
+ kName.add(new DERSequence(kSeq));
+ }
+
+ SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
+ keyS.add(kBag);
+ }
+
+ byte[] keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
+ BEROctetString keyString = new BEROctetString(keySEncoded);
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(cSalt);
+
+ ASN1EncodableVector certSeq = new ASN1EncodableVector();
+ PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+ Hashtable doneCerts = new Hashtable();
+
+ Enumeration cs = keys.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String name = (String)cs.nextElement();
+ Certificate cert = engineGetCertificate(name);
+ boolean cAttrSet = false;
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_localKeyId);
+ fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+ fName.add(new DERSequence(fSeq));
+
+ fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(name)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = certs.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String certId = (String)cs.nextElement();
+ Certificate cert = (Certificate)certs.get(certId);
+ boolean cAttrSet = false;
+
+ if (keys.get(certId) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(certId))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(certId)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = chainCerts.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ CertId certId = (CertId)cs.nextElement();
+ Certificate cert = (Certificate)chainCerts.get(certId);
+
+ if (doneCerts.get(cert) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+ }
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
+ byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
+ EncryptedData cInfo = new EncryptedData(data, cAlgId, new BEROctetString(certBytes));
+
+ ContentInfo[] info = new ContentInfo[]
+ {
+ new ContentInfo(data, keyString),
+ new ContentInfo(encryptedData, cInfo.toASN1Primitive())
+ };
+
+ AuthenticatedSafe auth = new AuthenticatedSafe(info);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream asn1Out;
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(bOut);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(bOut);
+ }
+
+ asn1Out.writeObject(auth);
+
+ byte[] pkg = bOut.toByteArray();
+
+ ContentInfo mainInfo = new ContentInfo(data, new BEROctetString(pkg));
+
+ //
+ // create the mac
+ //
+ byte[] mSalt = new byte[20];
+ int itCount = MIN_ITERATIONS;
+
+ random.nextBytes(mSalt);
+
+ byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+ MacData mData;
+
+ try
+ {
+ byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, DERNull.INSTANCE);
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mSalt, itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(stream);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(stream);
+ }
+
+ asn1Out.writeObject(pfx);
+ }
+
+ private static byte[] calculatePbeMac(
+ ASN1ObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ boolean wrongPkcs12Zero,
+ byte[] data)
+ throws Exception
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+ key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
+
+ Mac mac = Mac.getInstance(oid.getId(), bcProvider);
+ mac.init(key, defParams);
+ mac.update(data);
+ return mac.doFinal();
+ }
+
+ public static class BCPKCS12KeyStore
+ extends PKCS12KeyStoreSpi
+ {
+ public BCPKCS12KeyStore()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class BCPKCS12KeyStore3DES
+ extends PKCS12KeyStoreSpi
+ {
+ public BCPKCS12KeyStore3DES()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore
+ extends PKCS12KeyStoreSpi
+ {
+ public DefPKCS12KeyStore()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore3DES
+ extends PKCS12KeyStoreSpi
+ {
+ public DefPKCS12KeyStore3DES()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ private static class IgnoresCaseHashtable
+ {
+ private Hashtable orig = new Hashtable();
+ private Hashtable keys = new Hashtable();
+
+ public void put(String key, Object value)
+ {
+ String lower = (key == null) ? null : Strings.toLowerCase(key);
+ String k = (String)keys.get(lower);
+ if (k != null)
+ {
+ orig.remove(k);
+ }
+
+ keys.put(lower, key);
+ orig.put(key, value);
+ }
+
+ public Enumeration keys()
+ {
+ return orig.keys();
+ }
+
+ public Object remove(String alias)
+ {
+ String k = (String)keys.remove(alias == null ? null : Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.remove(k);
+ }
+
+ public Object get(String alias)
+ {
+ String k = (String)keys.get(alias == null ? null : Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.get(k);
+ }
+
+ public Enumeration elements()
+ {
+ return orig.elements();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/interfaces/ECKey.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/interfaces/ECKey.java
new file mode 100644
index 000000000..1cee721d2
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/interfaces/ECKey.java
@@ -0,0 +1,22 @@
+package org.spongycastle.jce.interfaces;
+
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+/**
+ * generic interface for an Elliptic Curve Key.
+ */
+public interface ECKey
+{
+ /**
+ * return a parameter specification representing the EC domain parameters
+ * for the key.
+ * @deprecated this method vanises in JDK 1.5. Use getParameters().
+ */
+ public ECParameterSpec getParams();
+
+ /**
+ * return a parameter specification representing the EC domain parameters
+ * for the key.
+ */
+ public ECParameterSpec getParameters();
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java
new file mode 100644
index 000000000..17adb3116
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java
@@ -0,0 +1,166 @@
+package org.spongycastle.jce.provider;
+
+import java.security.Permission;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.config.ProviderConfigurationPermission;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+class BouncyCastleProviderConfiguration
+ implements ProviderConfiguration
+{
+ private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+ private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.EC_IMPLICITLY_CA);
+ private static Permission BC_DH_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS);
+ private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS);
+
+ private ThreadLocal ecThreadSpec = new ThreadLocal();
+ private ThreadLocal dhThreadSpec = new ThreadLocal();
+
+ private volatile ECParameterSpec ecImplicitCaParams;
+ private volatile Object dhDefaultParams;
+
+ void setParameter(String parameterName, Object parameter)
+ {
+ SecurityManager securityManager = System.getSecurityManager();
+
+ if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+ {
+ ECParameterSpec curveSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
+ }
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ curveSpec = (ECParameterSpec)parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid ECParameterSpec");
+ }
+
+ if (curveSpec == null)
+ {
+ ecThreadSpec.set(null);
+ }
+ else
+ {
+ ecThreadSpec.set(curveSpec);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_PERMISSION);
+ }
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ ecImplicitCaParams = (ECParameterSpec)parameter;
+ }
+ else // assume java.security.spec
+ {
+ throw new IllegalArgumentException("not a valid ECParameterSpec");
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS))
+ {
+ Object dhSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_DH_LOCAL_PERMISSION);
+ }
+
+ if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+ {
+ dhSpec = parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec");
+ }
+
+ if (dhSpec == null)
+ {
+ dhThreadSpec.set(null);
+ }
+ else
+ {
+ dhThreadSpec.set(dhSpec);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.DH_DEFAULT_PARAMS))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_DH_PERMISSION);
+ }
+
+ if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+ {
+ dhDefaultParams = parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]");
+ }
+ }
+ }
+
+ public ECParameterSpec getEcImplicitlyCa()
+ {
+ ECParameterSpec spec = (ECParameterSpec)ecThreadSpec.get();
+
+ if (spec != null)
+ {
+ return spec;
+ }
+
+ return ecImplicitCaParams;
+ }
+
+ public DHParameterSpec getDHDefaultParameters(int keySize)
+ {
+ Object params = dhThreadSpec.get();
+ if (params == null)
+ {
+ params = dhDefaultParams;
+ }
+
+ if (params instanceof DHParameterSpec)
+ {
+ DHParameterSpec spec = (DHParameterSpec)params;
+
+ if (spec.getP().bitLength() == keySize)
+ {
+ return spec;
+ }
+ }
+ else if (params instanceof DHParameterSpec[])
+ {
+ DHParameterSpec[] specs = (DHParameterSpec[])params;
+
+ for (int i = 0; i != specs.length; i++)
+ {
+ if (specs[i].getP().bitLength() == keySize)
+ {
+ return specs[i];
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/CertPathValidatorUtilities.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
new file mode 100644
index 000000000..9faa1f7f3
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
@@ -0,0 +1,1439 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PolicyQualifierInfo;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEREnumerated;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.util.Integers;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+import org.spongycastle.x509.X509Store;
+
+public class CertPathValidatorUtilities
+{
+ protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+ protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+ protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+ protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+ protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+ protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+ protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+ protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+ protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+ protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+ protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+ protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+ protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ protected static final String ANY_POLICY = "2.5.29.32.0";
+
+ protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+ protected static final int CRL_SIGN = 6;
+
+ protected static final String[] crlReasons = new String[]{
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the default provider
+ * for signature verification.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors)
+ throws AnnotatedException
+ {
+ return findTrustAnchor(cert, trustAnchors, null);
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the specified
+ * provider for signature verification, or the default provider
+ * if null.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @param sigProvider the provider to use for signature verification
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors,
+ String sigProvider)
+ throws AnnotatedException
+ {
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+ X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
+
+ try
+ {
+ certSelectX509.setSubject(certIssuer.getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
+ }
+
+ Iterator iter = trustAnchors.iterator();
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X500Principal caName = new X500Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ verifyX509Certificate(cert, trustPublicKey, sigProvider);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ trustPublicKey = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ protected static void addAdditionalStoresFromAltNames(
+ X509Certificate cert,
+ ExtendedPKIXParameters pkixParams)
+ throws CertificateParsingException
+ {
+ // if in the IssuerAltName extension an URI
+ // is given, add an additinal X.509 store
+ if (cert.getIssuerAlternativeNames() != null)
+ {
+ Iterator it = cert.getIssuerAlternativeNames().iterator();
+ while (it.hasNext())
+ {
+ // look for URI
+ List list = (List)it.next();
+ if (list.get(0).equals(Integers.valueOf(GeneralName.uniformResourceIdentifier)))
+ {
+ // found
+ String temp = (String)list.get(1);
+ CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the issuer of an attribute certificate or certificate.
+ *
+ * @param cert The attribute certificate or certificate.
+ * @return The issuer as <code>X500Principal</code>.
+ */
+ protected static X500Principal getEncodedIssuerPrincipal(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getIssuerX500Principal();
+ }
+ else
+ {
+ return (X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0];
+ }
+ }
+
+ protected static Date getValidDate(PKIXParameters paramsPKIX)
+ {
+ Date validDate = paramsPKIX.getDate();
+
+ if (validDate == null)
+ {
+ validDate = new Date();
+ }
+
+ return validDate;
+ }
+
+ protected static X500Principal getSubjectPrincipal(X509Certificate cert)
+ {
+ return cert.getSubjectX500Principal();
+ }
+
+ protected static boolean isSelfIssued(X509Certificate cert)
+ {
+ return cert.getSubjectDN().equals(cert.getIssuerDN());
+ }
+
+
+ /**
+ * Extract the value of the given extension, if it exists.
+ *
+ * @param ext The extension object.
+ * @param oid The object identifier to obtain.
+ * @throws AnnotatedException if the extension cannot be read.
+ */
+ protected static ASN1Primitive getExtensionValue(
+ java.security.cert.X509Extension ext,
+ String oid)
+ throws AnnotatedException
+ {
+ byte[] bytes = ext.getExtensionValue(oid);
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ return getObject(oid, bytes);
+ }
+
+ private static ASN1Primitive getObject(
+ String oid,
+ byte[] ext)
+ throws AnnotatedException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(ext);
+ ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
+
+ aIn = new ASN1InputStream(octs.getOctets());
+ return aIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("exception processing extension " + oid, e);
+ }
+ }
+
+ protected static X500Principal getIssuerPrincipal(X509CRL crl)
+ {
+ return crl.getIssuerX500Principal();
+ }
+
+ protected static AlgorithmIdentifier getAlgorithmIdentifier(
+ PublicKey key)
+ throws CertPathValidatorException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ return info.getAlgorithmId();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
+ }
+ }
+
+ // crl checking
+
+
+ //
+ // policy checking
+ //
+
+ protected static final Set getQualifierSet(ASN1Sequence qualifiers)
+ throws CertPathValidatorException
+ {
+ Set pq = new HashSet();
+
+ if (qualifiers == null)
+ {
+ return pq;
+ }
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ Enumeration e = qualifiers.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
+ }
+ catch (IOException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+ }
+
+ bOut.reset();
+ }
+
+ return pq;
+ }
+
+ protected static PKIXPolicyNode removePolicyNode(
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
+
+ if (validPolicyTree == null)
+ {
+ return null;
+ }
+
+ if (_parent == null)
+ {
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ return null;
+ }
+ else
+ {
+ _parent.removeChild(_node);
+ removePolicyNodeRecurse(policyNodes, _node);
+
+ return validPolicyTree;
+ }
+ }
+
+ private static void removePolicyNodeRecurse(
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ policyNodes[_node.getDepth()].remove(_node);
+
+ if (_node.hasChildren())
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
+ removePolicyNodeRecurse(policyNodes, _child);
+ }
+ }
+ }
+
+
+ protected static boolean processCertD1i(
+ int index,
+ List[] policyNodes,
+ DERObjectIdentifier pOid,
+ Set pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
+ Set expectedPolicies = node.getExpectedPolicies();
+
+ if (expectedPolicies.contains(pOid.getId()))
+ {
+ Set childExpectedPolicies = new HashSet();
+ childExpectedPolicies.add(pOid.getId());
+
+ PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ childExpectedPolicies,
+ node,
+ pq,
+ pOid.getId(),
+ false);
+ node.addChild(child);
+ policyNodes[index].add(child);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected static void processCertD1ii(
+ int index,
+ List[] policyNodes,
+ DERObjectIdentifier _poid,
+ Set _pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Set _childExpectedPolicies = new HashSet();
+ _childExpectedPolicies.add(_poid.getId());
+
+ PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ _childExpectedPolicies,
+ _node,
+ _pq,
+ _poid.getId(),
+ false);
+ _node.addChild(_child);
+ policyNodes[index].add(_child);
+ return;
+ }
+ }
+ }
+
+ protected static void prepareNextCertB1(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ Map m_idp,
+ X509Certificate cert
+ )
+ throws AnnotatedException, CertPathValidatorException
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Certificate policies cannot be decoded.", e);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new AnnotatedException("Policy information cannot be decoded.", ex);
+ }
+ if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be built.", ex);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(
+ new ArrayList(), i,
+ (Set)m_idp.get(id_p),
+ p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode prepareNextCertB2(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ PKIXPolicyNode validPolicyTree)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return validPolicyTree;
+ }
+
+ protected static boolean isAnyPolicy(
+ Set policySet)
+ {
+ return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
+ }
+
+ protected static void addAdditionalStoreFromLocation(String location,
+ ExtendedPKIXParameters pkixParams)
+ {
+ if (pkixParams.isAdditionalLocationsEnabled())
+ {
+ try
+ {
+ if (location.startsWith("ldap://"))
+ {
+ // ldap://directory.d-trust.net/CN=D-TRUST
+ // Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE
+ // skip "ldap://"
+ location = location.substring(7);
+ // after first / baseDN starts
+ String base = null;
+ String url = null;
+ if (location.indexOf("/") != -1)
+ {
+ base = location.substring(location.indexOf("/"));
+ // URL
+ url = "ldap://"
+ + location.substring(0, location.indexOf("/"));
+ }
+ else
+ {
+ url = "ldap://" + location;
+ }
+ // use all purpose parameters
+ X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder(
+ url, base).build();
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CRL/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "ATTRIBUTECERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CERTIFICATEPAIR/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ }
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException("Exception adding X.509 stores.");
+ }
+ }
+ }
+
+ /**
+ * Return a Collection of all certificates or attribute certificates found
+ * in the X509Store's that are matching the certSelect criteriums.
+ *
+ * @param certSelect a {@link Selector} object that will be used to select
+ * the certificates
+ * @param certStores a List containing only {@link X509Store} objects. These
+ * are used to search for certificates.
+ * @return a Collection of all found {@link X509Certificate} or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} objects.
+ * May be empty but never <code>null</code>.
+ */
+ protected static Collection findCertificates(X509CertStoreSelector certSelect,
+ List certStores)
+ throws AnnotatedException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store certStore = (X509Store)obj;
+ try
+ {
+ certs.addAll(certStore.getMatches(certSelect));
+ }
+ catch (StoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+ else
+ {
+ CertStore certStore = (CertStore)obj;
+
+ try
+ {
+ certs.addAll(certStore.getCertificates(certSelect));
+ }
+ catch (CertStoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from certificate store.",
+ e);
+ }
+ }
+ }
+ return certs;
+ }
+
+ protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
+ List certStores)
+ throws AnnotatedException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store certStore = (X509Store)obj;
+ try
+ {
+ certs.addAll(certStore.getMatches(certSelect));
+ }
+ catch (StoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+ }
+ return certs;
+ }
+
+ protected static void addAdditionalStoresFromCRLDistributionPoint(
+ CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Distribution points could not be read.", e);
+ }
+ for (int i = 0; i < dps.length; i++)
+ {
+ DistributionPointName dpn = dps[i].getDistributionPoint();
+ // look for URIs in fullName
+ if (dpn != null)
+ {
+ if (dpn.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] genNames = GeneralNames.getInstance(
+ dpn.getName()).getNames();
+ // look for an URI
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
+ {
+ String location = DERIA5String.getInstance(
+ genNames[j].getName()).getString();
+ CertPathValidatorUtilities
+ .addAdditionalStoreFromLocation(location,
+ pkixParams);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add the CRL issuers from the cRLIssuer field of the distribution point or
+ * from the certificate if not given to the issuer criterion of the
+ * <code>selector</code>.
+ * <p/>
+ * The <code>issuerPrincipals</code> are a collection with a single
+ * <code>X500Principal</code> for <code>X509Certificate</code>s. For
+ * {@link X509AttributeCertificate}s the issuer may contain more than one
+ * <code>X500Principal</code>.
+ *
+ * @param dp The distribution point.
+ * @param issuerPrincipals The issuers of the certificate or attribute
+ * certificate which contains the distribution point.
+ * @param selector The CRL selector.
+ * @param pkixParams The PKIX parameters containing the cert stores.
+ * @throws AnnotatedException if an exception occurs while processing.
+ * @throws ClassCastException if <code>issuerPrincipals</code> does not
+ * contain only <code>X500Principal</code>s.
+ */
+ protected static void getCRLIssuersFromDistributionPoint(
+ DistributionPoint dp,
+ Collection issuerPrincipals,
+ X509CRLSelector selector,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ List issuers = new ArrayList();
+ // indirect CRL
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ // look for a DN
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ issuers.add(new X500Principal(genNames[j].getName()
+ .toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.",
+ e);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * certificate issuer is CRL issuer, distributionPoint field MUST be
+ * present.
+ */
+ if (dp.getDistributionPoint() == null)
+ {
+ throw new AnnotatedException(
+ "CRL issuer is omitted from distribution point but no distributionPoint field present.");
+ }
+ // add and check issuer principals
+ for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); )
+ {
+ issuers.add((X500Principal)it.next());
+ }
+ }
+ // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
+ // distributionPoint
+// if (dp.getDistributionPoint() != null)
+// {
+// // look for nameRelativeToCRLIssuer
+// if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+// {
+// // append fragment to issuer, only one
+// // issuer can be there, if this is given
+// if (issuers.size() != 1)
+// {
+// throw new AnnotatedException(
+// "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+// }
+// ASN1Encodable relName = dp.getDistributionPoint().getName();
+// Iterator it = issuers.iterator();
+// List issuersTemp = new ArrayList(issuers.size());
+// while (it.hasNext())
+// {
+// Enumeration e = null;
+// try
+// {
+// e = ASN1Sequence.getInstance(
+// new ASN1InputStream(((X500Principal) it.next())
+// .getEncoded()).readObject()).getObjects();
+// }
+// catch (IOException ex)
+// {
+// throw new AnnotatedException(
+// "Cannot decode CRL issuer information.", ex);
+// }
+// ASN1EncodableVector v = new ASN1EncodableVector();
+// while (e.hasMoreElements())
+// {
+// v.add((ASN1Encodable) e.nextElement());
+// }
+// v.add(relName);
+// issuersTemp.add(new X500Principal(new DERSequence(v)
+// .getDEREncoded()));
+// }
+// issuers.clear();
+// issuers.addAll(issuersTemp);
+// }
+// }
+ Iterator it = issuers.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ selector.addIssuerName(((X500Principal)it.next()).getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException(
+ "Cannot decode CRL issuer information.", ex);
+ }
+ }
+ }
+
+ private static BigInteger getSerialNumber(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getSerialNumber();
+ }
+ else
+ {
+ return ((X509AttributeCertificate)cert).getSerialNumber();
+ }
+ }
+
+ protected static void getCertStatus(
+ Date validDate,
+ X509CRL crl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ X509CRLEntry crl_entry = null;
+
+ boolean isIndirect;
+ try
+ {
+ isIndirect = X509CRLObject.isIndirectCRL(crl);
+ }
+ catch (CRLException exception)
+ {
+ throw new AnnotatedException("Failed check for indirect CRL.", exception);
+ }
+
+ if (isIndirect)
+ {
+ if (!(crl instanceof X509CRLObject))
+ {
+ try
+ {
+ crl = new X509CRLObject(CertificateList.getInstance(crl.getEncoded()));
+ }
+ catch (CRLException exception)
+ {
+ throw new AnnotatedException("Failed to recode indirect CRL.", exception);
+ }
+ }
+
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+
+ X500Principal certIssuer = ((X509CRLEntryObject)crl_entry).getCertificateIssuer();
+
+ if (certIssuer == null)
+ {
+ certIssuer = getIssuerPrincipal(crl);
+ }
+
+ if (!getEncodedIssuerPrincipal(cert).equals(certIssuer))
+ {
+ return;
+ }
+ }
+ else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl)))
+ {
+ return; // not for our issuer, ignore
+ }
+ else
+ {
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+ }
+
+ DEREnumerated reasonCode = null;
+ if (crl_entry.hasExtensions())
+ {
+ try
+ {
+ reasonCode = DEREnumerated
+ .getInstance(CertPathValidatorUtilities
+ .getExtensionValue(crl_entry,
+ X509Extension.reasonCode.getId()));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Reason code CRL entry extension could not be decoded.",
+ e);
+ }
+ }
+
+ // for reason keyCompromise, caCompromise, aACompromise or
+ // unspecified
+ if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
+ || reasonCode == null
+ || reasonCode.getValue().intValue() == 0
+ || reasonCode.getValue().intValue() == 1
+ || reasonCode.getValue().intValue() == 2
+ || reasonCode.getValue().intValue() == 8)
+ {
+
+ // (i) or (j) (1)
+ if (reasonCode != null)
+ {
+ certStatus.setCertStatus(reasonCode.getValue().intValue());
+ }
+ // (i) or (j) (2)
+ else
+ {
+ certStatus.setCertStatus(CRLReason.unspecified);
+ }
+ certStatus.setRevocationDate(crl_entry.getRevocationDate());
+ }
+ }
+
+ /**
+ * Fetches delta CRLs according to RFC 3280 section 5.2.4.
+ *
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @param completeCRL The complete CRL the delta CRL is for.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the delta
+ * CRLs.
+ */
+ protected static Set getDeltaCRLs(Date currentDate,
+ ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
+ throws AnnotatedException
+ {
+
+ X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector();
+
+ // 5.2.4 (a)
+ try
+ {
+ deltaSelect.addIssuerName(CertPathValidatorUtilities
+ .getIssuerPrincipal(completeCRL).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL.", e);
+ }
+
+ BigInteger completeCRLNumber = null;
+ try
+ {
+ ASN1Primitive derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
+ CRL_NUMBER);
+ if (derObject != null)
+ {
+ completeCRLNumber = ASN1Integer.getInstance(derObject).getPositiveValue();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "CRL number extension could not be extracted from CRL.", e);
+ }
+
+ // 5.2.4 (b)
+ byte[] idp = null;
+ try
+ {
+ idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension value could not be read.",
+ e);
+ }
+
+ // 5.2.4 (d)
+
+ deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber
+ .add(BigInteger.valueOf(1)));
+
+ deltaSelect.setIssuingDistributionPoint(idp);
+ deltaSelect.setIssuingDistributionPointEnabled(true);
+
+ // 5.2.4 (c)
+ deltaSelect.setMaxBaseCRLNumber(completeCRLNumber);
+
+ // find delta CRLs
+ Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate);
+
+ Set result = new HashSet();
+
+ for (Iterator it = temp.iterator(); it.hasNext(); )
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (isDeltaCRL(crl))
+ {
+ result.add(crl);
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean isDeltaCRL(X509CRL crl)
+ {
+ Set critical = crl.getCriticalExtensionOIDs();
+
+ if (critical == null)
+ {
+ return false;
+ }
+
+ return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ }
+
+ /**
+ * Fetches complete CRLs according to RFC 3280.
+ *
+ * @param dp The distribution point for which the complete CRL
+ * @param cert The <code>X509Certificate</code> or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} for
+ * which the CRL should be searched.
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with complete
+ * CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the CRLs
+ * or no CRLs are found.
+ */
+ protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
+ Date currentDate, ExtendedPKIXParameters paramsPKIX)
+ throws AnnotatedException
+ {
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ try
+ {
+ Set issuers = new HashSet();
+ if (cert instanceof X509AttributeCertificate)
+ {
+ issuers.add(((X509AttributeCertificate)cert)
+ .getIssuer().getPrincipals()[0]);
+ }
+ else
+ {
+ issuers.add(getEncodedIssuerPrincipal(cert));
+ }
+ CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Could not get issuer information from distribution point.", e);
+ }
+ if (cert instanceof X509Certificate)
+ {
+ crlselect.setCertificateChecking((X509Certificate)cert);
+ }
+ else if (cert instanceof X509AttributeCertificate)
+ {
+ crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert);
+ }
+
+
+ crlselect.setCompleteCRLEnabled(true);
+
+ Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
+ if (crls.isEmpty())
+ {
+ if (cert instanceof X509AttributeCertificate)
+ {
+ X509AttributeCertificate aCert = (X509AttributeCertificate)cert;
+
+ throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\"");
+ }
+ else
+ {
+ X509Certificate xCert = (X509Certificate)cert;
+
+ throw new AnnotatedException("No CRLs found for issuer \"" + xCert.getIssuerX500Principal() + "\"");
+ }
+ }
+ return crls;
+ }
+
+ protected static Date getValidCertDateFromValidityModel(
+ ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index)
+ throws AnnotatedException
+ {
+ if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ // if end cert use given signing/encryption/... time
+ if (index <= 0)
+ {
+ return CertPathValidatorUtilities.getValidDate(paramsPKIX);
+ // else use time when previous cert was created
+ }
+ else
+ {
+ if (index - 1 == 0)
+ {
+ DERGeneralizedTime dateOfCertgen = null;
+ try
+ {
+ byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId());
+ if (extBytes != null)
+ {
+ dateOfCertgen = DERGeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ if (dateOfCertgen != null)
+ {
+ try
+ {
+ return dateOfCertgen.getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new AnnotatedException(
+ "Date from date of cert gen extension could not be parsed.",
+ e);
+ }
+ }
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ else
+ {
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ }
+ }
+ else
+ {
+ return getValidDate(paramsPKIX);
+ }
+ }
+
+ /**
+ * Return the next working key inheriting DSA parameters if necessary.
+ * <p>
+ * This methods inherits DSA parameters from the indexed certificate or
+ * previous certificates in the certificate chain to the returned
+ * <code>PublicKey</code>. The list is searched upwards, meaning the end
+ * certificate is at position 0 and previous certificates are following.
+ * </p>
+ * <p>
+ * If the indexed certificate does not contain a DSA key this method simply
+ * returns the public key. If the DSA key already contains DSA parameters
+ * the key is also only returned.
+ * </p>
+ *
+ * @param certs The certification path.
+ * @param index The index of the certificate which contains the public key
+ * which should be extended with DSA parameters.
+ * @return The public key of the certificate in list position
+ * <code>index</code> extended with DSA parameters if applicable.
+ * @throws AnnotatedException if DSA parameters cannot be inherited.
+ */
+ protected static PublicKey getNextWorkingKey(List certs, int index)
+ throws CertPathValidatorException
+ {
+ Certificate cert = (Certificate)certs.get(index);
+ PublicKey pubKey = cert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ return pubKey;
+ }
+ DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey;
+ if (dsaPubKey.getParams() != null)
+ {
+ return dsaPubKey;
+ }
+ for (int i = index + 1; i < certs.size(); i++)
+ {
+ X509Certificate parentCert = (X509Certificate)certs.get(i);
+ pubKey = parentCert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ throw new CertPathValidatorException(
+ "DSA parameters cannot be inherited from previous certificate.");
+ }
+ DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey;
+ if (prevDSAPubKey.getParams() == null)
+ {
+ continue;
+ }
+ DSAParams dsaParams = prevDSAPubKey.getParams();
+ DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
+ dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+ try
+ {
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
+ return keyFactory.generatePublic(dsaPubKeySpec);
+ }
+ catch (Exception exception)
+ {
+ throw new RuntimeException(exception.getMessage());
+ }
+ }
+ throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ /**
+ * Find the issuer certificates of a given certificate.
+ *
+ * @param cert The certificate for which an issuer should be found.
+ * @param pkixParams
+ * @return A <code>Collection</code> object containing the issuer
+ * <code>X509Certificate</code>s. Never <code>null</code>.
+ * @throws AnnotatedException if an error occurs.
+ */
+ protected static Collection findIssuerCerts(
+ X509Certificate cert,
+ ExtendedPKIXBuilderParameters pkixParams)
+ throws AnnotatedException
+ {
+ X509CertStoreSelector certSelect = new X509CertStoreSelector();
+ Set certs = new HashSet();
+ try
+ {
+ certSelect.setSubject(cert.getIssuerX500Principal().getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+ }
+
+ Iterator iter;
+
+ try
+ {
+ List matches = new ArrayList();
+
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getCertStores()));
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getStores()));
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getAdditionalStores()));
+
+ iter = matches.iterator();
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate cannot be searched.", e);
+ }
+
+ X509Certificate issuer = null;
+ while (iter.hasNext())
+ {
+ issuer = (X509Certificate)iter.next();
+ // issuer cannot be verified because possible DSA inheritance
+ // parameters are missing
+ certs.add(issuer);
+ }
+ return certs;
+ }
+
+ protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
+ String sigProvider)
+ throws GeneralSecurityException
+ {
+ if (sigProvider == null)
+ {
+ cert.verify(publicKey);
+ }
+ else
+ {
+ cert.verify(publicKey, sigProvider);
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/JDKPKCS12KeyStore.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/JDKPKCS12KeyStore.java
new file mode 100644
index 000000000..5efc5ea83
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/JDKPKCS12KeyStore.java
@@ -0,0 +1,1565 @@
+package org.spongycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+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.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BERConstructedOctetString;
+import org.spongycastle.asn1.BEROutputStream;
+import org.spongycastle.asn1.DERBMPString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.AuthenticatedSafe;
+import org.spongycastle.asn1.pkcs.CertBag;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.EncryptedData;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jce.interfaces.BCKeyStore;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.encoders.Hex;
+
+public class JDKPKCS12KeyStore
+ extends KeyStoreSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+ private static final int SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private static final Provider bcProvider = new BouncyCastleProvider();
+
+ private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private Hashtable localIds = new Hashtable();
+ private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private Hashtable chainCerts = new Hashtable();
+ private Hashtable keyCerts = new Hashtable();
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected SecureRandom random = new SecureRandom();
+
+ // use of final causes problems with JDK 1.2 compiler
+ private CertificateFactory certFact;
+ private ASN1ObjectIdentifier keyAlgorithm;
+ private ASN1ObjectIdentifier certAlgorithm;
+
+ private class CertId
+ {
+ byte[] id;
+
+ CertId(
+ PublicKey key)
+ {
+ this.id = createSubjectKeyId(key).getKeyIdentifier();
+ }
+
+ CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(id);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof CertId))
+ {
+ return false;
+ }
+
+ CertId cId = (CertId)o;
+
+ return Arrays.areEqual(id, cId.id);
+ }
+ }
+
+ public JDKPKCS12KeyStore(
+ Provider provider,
+ ASN1ObjectIdentifier keyAlgorithm,
+ ASN1ObjectIdentifier certAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+
+ try
+ {
+ if (provider != null)
+ {
+ certFact = CertificateFactory.getInstance("X.509", provider);
+ }
+ else
+ {
+ certFact = CertificateFactory.getInstance("X.509");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+ }
+ }
+
+ private SubjectKeyIdentifier createSubjectKeyId(
+ PublicKey pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(
+ (ASN1Sequence) ASN1Primitive.fromByteArray(pubKey.getEncoded()));
+
+ return new SubjectKeyIdentifier(info);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error creating key");
+ }
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (certs.get(alias) != null || keys.get(alias) != null);
+ }
+
+ /**
+ * this is not quite complete - we should follow up on the chain, a bit
+ * tricky if a certificate appears in more than one chain...
+ */
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Key k = (Key)keys.remove(alias);
+
+ Certificate c = (Certificate)certs.remove(alias);
+
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+
+ if (k != null)
+ {
+ String id = (String)localIds.remove(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.remove(id);
+ }
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+ }
+
+ if (c == null && k == null)
+ {
+ throw new KeyStoreException("no such entry as " + alias);
+ }
+ }
+
+ /**
+ * simply return the cert for the private key
+ */
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificate.");
+ }
+
+ Certificate c = (Certificate)certs.get(alias);
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ String id = (String)localIds.get(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.get(id);
+ }
+ else
+ {
+ c = (Certificate)keyCerts.get(alias);
+ }
+ }
+
+ return c;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration c = certs.elements();
+ Enumeration k = certs.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ c = keyCerts.elements();
+ k = keyCerts.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+ }
+
+ if (!engineIsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ Certificate c = engineGetCertificate(alias);
+
+ if (c != null)
+ {
+ Vector cs = new Vector();
+
+ while (c != null)
+ {
+ X509Certificate x509c = (X509Certificate)c;
+ Certificate nextC = null;
+
+ byte[] bytes = x509c.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(bytes);
+
+ byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+ aIn = new ASN1InputStream(authBytes);
+
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject());
+ if (id.getKeyIdentifier() != null)
+ {
+ nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+ }
+
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ Principal i = x509c.getIssuerDN();
+ Principal s = x509c.getSubjectDN();
+
+ if (!i.equals(s))
+ {
+ Enumeration e = chainCerts.keys();
+
+ while (e.hasMoreElements())
+ {
+ X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+ Principal sub = crt.getSubjectDN();
+ if (sub.equals(i))
+ {
+ try
+ {
+ x509c.verify(crt.getPublicKey());
+ nextC = crt;
+ break;
+ }
+ catch (Exception ex)
+ {
+ // continue
+ }
+ }
+ }
+ }
+ }
+
+ cs.addElement(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ Certificate[] certChain = new Certificate[cs.size()];
+
+ for (int i = 0; i != certChain.length; i++)
+ {
+ certChain[i] = (Certificate)cs.elementAt(i);
+ }
+
+ return certChain;
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ return new Date();
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getKey.");
+ }
+
+ return (Key)keys.get(alias);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ return (certs.get(alias) != null && keys.get(alias) == null);
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ return (keys.get(alias) != null);
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ if (keys.get(alias) != null)
+ {
+ throw new KeyStoreException("There is a key entry with the name " + alias + ".");
+ }
+
+ certs.put(alias, cert);
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ throw new RuntimeException("operation not supported");
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ if (keys.get(alias) != null)
+ {
+ engineDeleteEntry(alias);
+ }
+
+ keys.put(alias, key);
+ certs.put(alias, chain[0]);
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+ }
+ }
+
+ public int engineSize()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.size();
+ }
+
+ protected PrivateKey unwrapKey(
+ AlgorithmIdentifier algId,
+ byte[] data,
+ char[] password,
+ boolean wrongPKCS12Zero)
+ throws IOException
+ {
+ String algorithm = algId.getObjectId().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PrivateKey out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ SecretKey k = keyFact.generateSecret(pbeSpec);
+
+ ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ out = (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception unwrapping private key - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] wrapKey(
+ String algorithm,
+ Key key,
+ PKCS12PBEParams pbeParams,
+ char[] password)
+ throws IOException
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ byte[] out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+ out = cipher.wrap(key);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception encrypting data - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] cryptData(
+ boolean forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ boolean wrongPKCS12Zero,
+ byte[] data)
+ throws IOException
+ {
+ String algorithm = algId.getObjectId().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+ BCPBEKey key = (BCPBEKey) keyFact.generateSecret(pbeSpec);
+
+ key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+ int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+ cipher.init(mode, key, defParams);
+ return cipher.doFinal(data);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decrypting data - " + e.toString());
+ }
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+ bufIn.mark(10);
+
+ int head = bufIn.read();
+
+ if (head != 0x30)
+ {
+ throw new IOException("stream does not represent a PKCS12 key store");
+ }
+
+ bufIn.reset();
+
+ ASN1InputStream bIn = new ASN1InputStream(bufIn);
+ ASN1Sequence obj = (ASN1Sequence)bIn.readObject();
+ Pfx bag = Pfx.getInstance(obj);
+ ContentInfo info = bag.getAuthSafe();
+ Vector chain = new Vector();
+ boolean unmarkedKey = false;
+ boolean wrongPKCS12Zero = false;
+
+ if (bag.getMacData() != null) // check the mac code
+ {
+ MacData mData = bag.getMacData();
+ DigestInfo dInfo = mData.getMac();
+ AlgorithmIdentifier algId = dInfo.getAlgorithmId();
+ byte[] salt = mData.getSalt();
+ int itCount = mData.getIterationCount().intValue();
+
+ byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
+
+ try
+ {
+ byte[] res = calculatePbeMac(algId.getObjectId(), salt, itCount, password, false, data);
+ byte[] dig = dInfo.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ if (password.length > 0)
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ // Try with incorrect zero length password
+ res = calculatePbeMac(algId.getObjectId(), salt, itCount, password, true, data);
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ wrongPKCS12Zero = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+ }
+
+ keys = new IgnoresCaseHashtable();
+ localIds = new Hashtable();
+
+ if (info.getContentType().equals(data))
+ {
+ bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+ AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
+ ContentInfo[] c = authSafe.getContentInfo();
+
+ for (int i = 0; i != c.length; i++)
+ {
+ if (c[i].getContentType().equals(data))
+ {
+ ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+ if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Object attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Object)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ unmarkedKey = true;
+ keys.put("unmarked", privKey);
+ }
+ }
+ else if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else
+ {
+ System.out.println("extra in data " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else if (c[i].getContentType().equals(encryptedData))
+ {
+ EncryptedData d = EncryptedData.getInstance(c[i].getContent());
+ byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
+ password, wrongPKCS12Zero, d.getContent().getOctets());
+ ASN1Sequence seq = (ASN1Sequence) ASN1Primitive.fromByteArray(octets);
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+ if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet= (ASN1Set)sq.getObjectAt(1);
+ ASN1Object attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Object)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else if (b.getBagId().equals(keyBag))
+ {
+ org.spongycastle.asn1.pkcs.PrivateKeyInfo kInfo = new org.spongycastle.asn1.pkcs.PrivateKeyInfo((ASN1Sequence)b.getBagValue());
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Object attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Object)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ System.out.println("extra in encryptedData " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else
+ {
+ System.out.println("extra " + c[i].getContentType().getId());
+ System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+ }
+ }
+ }
+
+ certs = new IgnoresCaseHashtable();
+ chainCerts = new Hashtable();
+ keyCerts = new Hashtable();
+
+ for (int i = 0; i != chain.size(); i++)
+ {
+ SafeBag b = (SafeBag)chain.elementAt(i);
+ CertBag cb = CertBag.getInstance(b.getBagValue());
+
+ if (!cb.getCertId().equals(x509Certificate))
+ {
+ throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
+ }
+
+ Certificate cert;
+
+ try
+ {
+ ByteArrayInputStream cIn = new ByteArrayInputStream(
+ ((ASN1OctetString)cb.getCertValue()).getOctets());
+ cert = certFact.generateCertificate(cIn);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+
+ //
+ // set the attributes
+ //
+ ASN1OctetString localId = null;
+ String alias = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Object attr = (ASN1Object)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
+ PKCS12BagAttributeCarrier bagAttr = null;
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(oid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(oid, attr);
+ }
+ }
+
+ if (oid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ }
+ else if (oid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+ if (unmarkedKey)
+ {
+ if (keyCerts.isEmpty())
+ {
+ String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+
+ keyCerts.put(name, cert);
+ keys.put(name, keys.remove("unmarked"));
+ }
+ }
+ else
+ {
+ //
+ // the local key id needs to override the friendly name
+ //
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ keyCerts.put(name, cert);
+ }
+ if (alias != null)
+ {
+ certs.put(alias, cert);
+ }
+ }
+ }
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ //
+ // handle the key
+ //
+ ASN1EncodableVector keyS = new ASN1EncodableVector();
+
+
+ Enumeration ks = keys.keys();
+
+ while (ks.hasMoreElements())
+ {
+ byte[] kSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(kSalt);
+
+ String name = (String)ks.nextElement();
+ PrivateKey privKey = (PrivateKey)keys.get(name);
+ PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+ byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+ AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Object());
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+ boolean attrSet = false;
+ ASN1EncodableVector kName = new ASN1EncodableVector();
+
+ if (privKey instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ Certificate ct = engineGetCertificate(name);
+
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+
+ kSeq.add(oid);
+ kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+ attrSet = true;
+
+ kName.add(new DERSequence(kSeq));
+ }
+ }
+
+ if (!attrSet)
+ {
+ //
+ // set a default friendly name (from the key id) and local id
+ //
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+ Certificate ct = engineGetCertificate(name);
+
+ kSeq.add(pkcs_9_at_localKeyId);
+ kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+ kName.add(new DERSequence(kSeq));
+
+ kSeq = new ASN1EncodableVector();
+
+ kSeq.add(pkcs_9_at_friendlyName);
+ kSeq.add(new DERSet(new DERBMPString(name)));
+
+ kName.add(new DERSequence(kSeq));
+ }
+
+ SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Object(), new DERSet(kName));
+ keyS.add(kBag);
+ }
+
+ byte[] keySEncoded = new DERSequence(keyS).getEncoded();
+ BERConstructedOctetString keyString = new BERConstructedOctetString(keySEncoded);
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(cSalt);
+
+ ASN1EncodableVector certSeq = new ASN1EncodableVector();
+ PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Object());
+ Hashtable doneCerts = new Hashtable();
+
+ Enumeration cs = keys.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String name = (String)cs.nextElement();
+ Certificate cert = engineGetCertificate(name);
+ boolean cAttrSet = false;
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_localKeyId);
+ fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+ fName.add(new DERSequence(fSeq));
+
+ fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(name)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Object(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = certs.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String certId = (String)cs.nextElement();
+ Certificate cert = (Certificate)certs.get(certId);
+ boolean cAttrSet = false;
+
+ if (keys.get(certId) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(certId))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(certId)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Object(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = chainCerts.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ CertId certId = (CertId)cs.nextElement();
+ Certificate cert = (Certificate)chainCerts.get(certId);
+
+ if (doneCerts.get(cert) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+ }
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Object(), new DERSet(fName));
+
+ certSeq.add(sBag);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded();
+ byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
+ EncryptedData cInfo = new EncryptedData(data, cAlgId, new BERConstructedOctetString(certBytes));
+
+ ContentInfo[] info = new ContentInfo[]
+ {
+ new ContentInfo(data, keyString),
+ new ContentInfo(encryptedData, cInfo.toASN1Object())
+ };
+
+ AuthenticatedSafe auth = new AuthenticatedSafe(info);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ BEROutputStream berOut = new BEROutputStream(bOut);
+
+ berOut.writeObject(auth);
+
+ byte[] pkg = bOut.toByteArray();
+
+ ContentInfo mainInfo = new ContentInfo(data, new BERConstructedOctetString(pkg));
+
+ //
+ // create the mac
+ //
+ byte[] mSalt = new byte[20];
+ int itCount = MIN_ITERATIONS;
+
+ random.nextBytes(mSalt);
+
+ byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+ MacData mData;
+
+ try
+ {
+ byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, new DERNull());
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mSalt, itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ berOut = new BEROutputStream(stream);
+
+ berOut.writeObject(pfx);
+ }
+
+ private static byte[] calculatePbeMac(
+ ASN1ObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ boolean wrongPkcs12Zero,
+ byte[] data)
+ throws Exception
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ BCPBEKey key = (BCPBEKey) keyFact.generateSecret(pbeSpec);
+ key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
+
+ Mac mac = Mac.getInstance(oid.getId(), bcProvider);
+ mac.init(key, defParams);
+ mac.update(data);
+ return mac.doFinal();
+ }
+
+ public static class BCPKCS12KeyStore
+ extends JDKPKCS12KeyStore
+ {
+ public BCPKCS12KeyStore()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class BCPKCS12KeyStore3DES
+ extends JDKPKCS12KeyStore
+ {
+ public BCPKCS12KeyStore3DES()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore
+ extends JDKPKCS12KeyStore
+ {
+ public DefPKCS12KeyStore()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore3DES
+ extends JDKPKCS12KeyStore
+ {
+ public DefPKCS12KeyStore3DES()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ private static class IgnoresCaseHashtable
+ {
+ private Hashtable orig = new Hashtable();
+ private Hashtable keys = new Hashtable();
+
+ public void put(String key, Object value)
+ {
+ String lower = Strings.toLowerCase(key);
+ String k = (String)keys.get(lower);
+ if (k != null)
+ {
+ orig.remove(k);
+ }
+
+ keys.put(lower, key);
+ orig.put(key, value);
+ }
+
+ public Enumeration keys()
+ {
+ return orig.keys();
+ }
+
+ public Object remove(String alias)
+ {
+ String k = (String)keys.remove(Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.remove(k);
+ }
+
+ public Object get(String alias)
+ {
+ String k = (String)keys.get(Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.get(k);
+ }
+
+ public Enumeration elements()
+ {
+ return orig.elements();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/X509SignatureUtil.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/X509SignatureUtil.java
new file mode 100644
index 000000000..48d24344d
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/jce/provider/X509SignatureUtil.java
@@ -0,0 +1,125 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DERObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+class X509SignatureUtil
+{
+ private static final ASN1Null derNull = new DERNull();
+
+ static void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !derNull.equals(params))
+ {
+ /*
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+ try
+ {
+ sigParams.init(params.getDERObject().getDEREncoded());
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+
+ try
+ {
+ signature.setParameters(sigParams.getParameterSpec(PSSParameterSpec.class));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+ }
+ */
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ DERObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/X509CRLStoreSelector.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/X509CRLStoreSelector.java
new file mode 100644
index 000000000..c4172969f
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/X509CRLStoreSelector.java
@@ -0,0 +1,330 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.asn1.DERInteger;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRL;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLSelector;
+
+/**
+ * This class is a Selector implementation for X.509 certificate revocation
+ * lists.
+ *
+ * @see org.spongycastle.util.Selector
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.jce.provider.X509StoreCRLCollection
+ */
+public class X509CRLStoreSelector
+ extends X509CRLSelector
+ implements Selector
+{
+ private boolean deltaCRLIndicator = false;
+
+ private boolean completeCRLEnabled = false;
+
+ private BigInteger maxBaseCRLNumber = null;
+
+ private byte[] issuingDistributionPoint = null;
+
+ private boolean issuingDistributionPointEnabled = false;
+
+ private X509AttributeCertificate attrCertChecking;
+
+ /**
+ * Returns if the issuing distribution point criteria should be applied.
+ * Defaults to <code>false</code>.
+ * <p>
+ * You may also set the issuing distribution point criteria if not a missing
+ * issuing distribution point should be assumed.
+ *
+ * @return Returns if the issuing distribution point check is enabled.
+ */
+ public boolean isIssuingDistributionPointEnabled()
+ {
+ return issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Enables or disables the issuing distribution point check.
+ *
+ * @param issuingDistributionPointEnabled <code>true</code> to enable the
+ * issuing distribution point check.
+ */
+ public void setIssuingDistributionPointEnabled(
+ boolean issuingDistributionPointEnabled)
+ {
+ this.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Sets the attribute certificate being checked. This is not a criterion.
+ * Rather, it is optional information that may help a {@link X509Store} find
+ * CRLs that would be relevant when checking revocation for the specified
+ * attribute certificate. If <code>null</code> is specified, then no such
+ * optional information is provided.
+ *
+ * @param attrCert the <code>X509AttributeCertificate</code> being checked (or
+ * <code>null</code>)
+ * @see #getAttrCertificateChecking()
+ */
+ public void setAttrCertificateChecking(X509AttributeCertificate attrCert)
+ {
+ attrCertChecking = attrCert;
+ }
+
+ /**
+ * Returns the attribute certificate being checked.
+ *
+ * @return Returns the attribute certificate being checked.
+ * @see #setAttrCertificateChecking(X509AttributeCertificate)
+ */
+ public X509AttributeCertificate getAttrCertificateChecking()
+ {
+ return attrCertChecking;
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509CRL))
+ {
+ return false;
+ }
+ X509CRL crl = (X509CRL)obj;
+ DERInteger dci = null;
+ try
+ {
+ byte[] bytes = crl
+ .getExtensionValue(X509Extensions.DeltaCRLIndicator.getId());
+ if (bytes != null)
+ {
+ dci = DERInteger.getInstance(X509ExtensionUtil
+ .fromExtensionValue(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ if (isDeltaCRLIndicatorEnabled())
+ {
+ if (dci == null)
+ {
+ return false;
+ }
+ }
+ if (isCompleteCRLEnabled())
+ {
+ if (dci != null)
+ {
+ return false;
+ }
+ }
+ if (dci != null)
+ {
+
+ if (maxBaseCRLNumber != null)
+ {
+ if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1)
+ {
+ return false;
+ }
+ }
+ }
+ if (issuingDistributionPointEnabled)
+ {
+ byte[] idp = crl
+ .getExtensionValue(X509Extensions.IssuingDistributionPoint
+ .getId());
+ if (issuingDistributionPoint == null)
+ {
+ if (idp != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!Arrays.areEqual(idp, issuingDistributionPoint))
+ {
+ return false;
+ }
+ }
+
+ }
+ return super.match((X509CRL)obj);
+ }
+
+ public boolean match(CRL crl)
+ {
+ return match((Object)crl);
+ }
+
+ /**
+ * Returns if this selector must match CRLs with the delta CRL indicator
+ * extension set. Defaults to <code>false</code>.
+ *
+ * @return Returns <code>true</code> if only CRLs with the delta CRL
+ * indicator extension are selected.
+ */
+ public boolean isDeltaCRLIndicatorEnabled()
+ {
+ return deltaCRLIndicator;
+ }
+
+ /**
+ * If this is set to <code>true</code> the CRL reported contains the delta
+ * CRL indicator CRL extension.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator
+ * extension must be in the CRL.
+ */
+ public void setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator)
+ {
+ this.deltaCRLIndicator = deltaCRLIndicator;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CRLSelector</code>.
+ *
+ * @param selector A <code>X509CRLSelector</code> instance.
+ * @return An instance of an <code>X509CRLStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation
+ * fails.
+ */
+ public static X509CRLStoreSelector getInstance(X509CRLSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException(
+ "cannot create from null selector");
+ }
+ X509CRLStoreSelector cs = new X509CRLStoreSelector();
+ cs.setCertificateChecking(selector.getCertificateChecking());
+ cs.setDateAndTime(selector.getDateAndTime());
+ try
+ {
+ cs.setIssuerNames(selector.getIssuerNames());
+ }
+ catch (IOException e)
+ {
+ // cannot happen
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ //cs.setIssuers(selector.getIssuers());
+ cs.setMaxCRLNumber(selector.getMaxCRL());
+ cs.setMinCRLNumber(selector.getMinCRL());
+ return cs;
+ }
+
+ public Object clone()
+ {
+ X509CRLStoreSelector sel = X509CRLStoreSelector.getInstance(this);
+ sel.deltaCRLIndicator = deltaCRLIndicator;
+ sel.completeCRLEnabled = completeCRLEnabled;
+ sel.maxBaseCRLNumber = maxBaseCRLNumber;
+ sel.attrCertChecking = attrCertChecking;
+ sel.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ sel.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ return sel;
+ }
+
+ /**
+ * If <code>true</code> only complete CRLs are returned. Defaults to
+ * <code>false</code>.
+ *
+ * @return <code>true</code> if only complete CRLs are returned.
+ */
+ public boolean isCompleteCRLEnabled()
+ {
+ return completeCRLEnabled;
+ }
+
+ /**
+ * If set to <code>true</code> only complete CRLs are returned.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param completeCRLEnabled <code>true</code> if only complete CRLs
+ * should be returned.
+ */
+ public void setCompleteCRLEnabled(boolean completeCRLEnabled)
+ {
+ this.completeCRLEnabled = completeCRLEnabled;
+ }
+
+ /**
+ * Get the maximum base CRL number. Defaults to <code>null</code>.
+ *
+ * @return Returns the maximum base CRL number.
+ * @see #setMaxBaseCRLNumber(BigInteger)
+ */
+ public BigInteger getMaxBaseCRLNumber()
+ {
+ return maxBaseCRLNumber;
+ }
+
+ /**
+ * Sets the maximum base CRL number. Setting to <code>null</code> disables
+ * this cheack.
+ * <p>
+ * This is only meaningful for delta CRLs. Complete CRLs must have a CRL
+ * number which is greater or equal than the base number of the
+ * corresponding CRL.
+ *
+ * @param maxBaseCRLNumber The maximum base CRL number to set.
+ */
+ public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber)
+ {
+ this.maxBaseCRLNumber = maxBaseCRLNumber;
+ }
+
+ /**
+ * Returns the issuing distribution point. Defaults to <code>null</code>,
+ * which is a missing issuing distribution point extension.
+ * <p>
+ * The internal byte array is cloned before it is returned.
+ * <p>
+ * The criteria must be enable with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @return Returns the issuing distribution point.
+ * @see #setIssuingDistributionPoint(byte[])
+ */
+ public byte[] getIssuingDistributionPoint()
+ {
+ return Arrays.clone(issuingDistributionPoint);
+ }
+
+ /**
+ * Sets the issuing distribution point.
+ * <p>
+ * The issuing distribution point extension is a CRL extension which
+ * identifies the scope and the distribution point of a CRL. The scope
+ * contains among others information about revocation reasons contained in
+ * the CRL. Delta CRLs and complete CRLs must have matching issuing
+ * distribution points.
+ * <p>
+ * The byte array is cloned to protect against subsequent modifications.
+ * <p>
+ * You must also enable or disable this criteria with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @param issuingDistributionPoint The issuing distribution point to set.
+ * This is the DER encoded OCTET STRING extension value.
+ * @see #getIssuingDistributionPoint()
+ */
+ public void setIssuingDistributionPoint(byte[] issuingDistributionPoint)
+ {
+ this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/X509CertStoreSelector.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/X509CertStoreSelector.java
new file mode 100644
index 000000000..61664c449
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/X509CertStoreSelector.java
@@ -0,0 +1,86 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.io.IOException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+
+/**
+ * This class is a Selector implementation for X.509 certificates.
+ *
+ * @see org.spongycastle.util.Selector
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.jce.provider.X509StoreCertCollection
+ */
+public class X509CertStoreSelector
+ extends X509CertSelector
+ implements Selector
+{
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate other = (X509Certificate)obj;
+
+ return super.match(other);
+ }
+
+ public boolean match(Certificate cert)
+ {
+ return match((Object)cert);
+ }
+
+ public Object clone()
+ {
+ X509CertStoreSelector selector = (X509CertStoreSelector)super.clone();
+
+ return selector;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CertSelector</code>.
+ *
+ * @param selector A <code>X509CertSelector</code> instance.
+ * @return An instance of an <code>X509CertStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation fails.
+ */
+ public static X509CertStoreSelector getInstance(X509CertSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException("cannot create from null selector");
+ }
+ X509CertStoreSelector cs = new X509CertStoreSelector();
+ cs.setAuthorityKeyIdentifier(selector.getAuthorityKeyIdentifier());
+ cs.setBasicConstraints(selector.getBasicConstraints());
+ cs.setCertificate(selector.getCertificate());
+ cs.setCertificateValid(selector.getCertificateValid());
+ cs.setMatchAllSubjectAltNames(selector.getMatchAllSubjectAltNames());
+ try
+ {
+ cs.setPathToNames(selector.getPathToNames());
+ cs.setExtendedKeyUsage(selector.getExtendedKeyUsage());
+ cs.setNameConstraints(selector.getNameConstraints());
+ cs.setPolicy(selector.getPolicy());
+ cs.setSubjectPublicKeyAlgID(selector.getSubjectPublicKeyAlgID());
+ cs.setIssuer(selector.getIssuerAsBytes());
+ cs.setSubject(selector.getSubjectAsBytes());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error in passed in selector: " + e);
+ }
+ cs.setKeyUsage(selector.getKeyUsage());
+ cs.setPrivateKeyValid(selector.getPrivateKeyValid());
+ cs.setSerialNumber(selector.getSerialNumber());
+ cs.setSubjectKeyIdentifier(selector.getSubjectKeyIdentifier());
+ cs.setSubjectPublicKey(selector.getSubjectPublicKey());
+ return cs;
+ }
+
+}
diff --git a/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/util/LDAPStoreHelper.java b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/util/LDAPStoreHelper.java
new file mode 100644
index 000000000..b78c4a765
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.4/org/spongycastle/x509/util/LDAPStoreHelper.java
@@ -0,0 +1,1118 @@
+package org.spongycastle.x509.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.sql.Date;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificatePair;
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.jce.provider.X509AttrCertParser;
+import org.spongycastle.jce.provider.X509CRLParser;
+import org.spongycastle.jce.provider.X509CertPairParser;
+import org.spongycastle.jce.provider.X509CertParser;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertPairStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+import org.spongycastle.x509.X509CertificatePair;
+
+/**
+ * This is a general purpose implementation to get X.509 certificates, CRLs,
+ * attribute certificates and cross certificates from a LDAP location.
+ * <p/>
+ * At first a search is performed in the ldap*AttributeNames of the
+ * {@link org.spongycastle.jce.X509LDAPCertStoreParameters} with the given
+ * information of the subject (for all kind of certificates) or issuer (for
+ * CRLs), respectively, if a {@link org.spongycastle.x509.X509CertStoreSelector} or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} is given with that
+ * details.
+ * <p/>
+ * For the used schemes see:
+ * <ul>
+ * <li><a href="http://www.ietf.org/rfc/rfc2587.txt">RFC 2587</a>
+ * <li><a
+ * href="http://www3.ietf.org/proceedings/01mar/I-D/pkix-ldap-schema-01.txt">Internet
+ * X.509 Public Key Infrastructure Additional LDAP Schema for PKIs and PMIs</a>
+ * </ul>
+ */
+public class LDAPStoreHelper
+{
+
+ // TODO: cache results
+
+ private X509LDAPCertStoreParameters params;
+
+ public LDAPStoreHelper(X509LDAPCertStoreParameters params)
+ {
+ this.params = params;
+ }
+
+ /**
+ * Initial Context Factory.
+ */
+ private static String LDAP_PROVIDER = "com.sun.jndi.ldap.LdapCtxFactory";
+
+ /**
+ * Processing referrals..
+ */
+ private static String REFERRALS_IGNORE = "ignore";
+
+ /**
+ * Security level to be used for LDAP connections.
+ */
+ private static final String SEARCH_SECURITY_LEVEL = "none";
+
+ /**
+ * Package Prefix for loading URL context factories.
+ */
+ private static final String URL_CONTEXT_PREFIX = "com.sun.jndi.url";
+
+ private DirContext connectLDAP() throws NamingException
+ {
+ Properties props = new Properties();
+ props.setProperty(Context.INITIAL_CONTEXT_FACTORY, LDAP_PROVIDER);
+ props.setProperty(Context.BATCHSIZE, "0");
+
+ props.setProperty(Context.PROVIDER_URL, params.getLdapURL());
+ props.setProperty(Context.URL_PKG_PREFIXES, URL_CONTEXT_PREFIX);
+ props.setProperty(Context.REFERRAL, REFERRALS_IGNORE);
+ props.setProperty(Context.SECURITY_AUTHENTICATION,
+ SEARCH_SECURITY_LEVEL);
+
+ DirContext ctx = new InitialDirContext(props);
+ return ctx;
+ }
+
+ private String parseDN(String subject, String dNAttributeName)
+ {
+ String temp = subject;
+ int begin = temp.toLowerCase().indexOf(
+ dNAttributeName.toLowerCase() + "=");
+ if (begin == -1)
+ {
+ return "";
+ }
+ temp = temp.substring(begin + dNAttributeName.length());
+ int end = temp.indexOf(',');
+ if (end == -1)
+ {
+ end = temp.length();
+ }
+ while (temp.charAt(end - 1) == '\\')
+ {
+ end = temp.indexOf(',', end + 1);
+ if (end == -1)
+ {
+ end = temp.length();
+ }
+ }
+ temp = temp.substring(0, end);
+ begin = temp.indexOf('=');
+ temp = temp.substring(begin + 1);
+ if (temp.charAt(0) == ' ')
+ {
+ temp = temp.substring(1);
+ }
+ if (temp.startsWith("\""))
+ {
+ temp = temp.substring(1);
+ }
+ if (temp.endsWith("\""))
+ {
+ temp = temp.substring(0, temp.length() - 1);
+ }
+ return temp;
+ }
+
+ private Set createCerts(List list, X509CertStoreSelector xselector)
+ throws StoreException
+ {
+ Set certSet = new HashSet();
+
+ Iterator it = list.iterator();
+ X509CertParser parser = new X509CertParser();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509Certificate cert = (X509Certificate)parser
+ .engineRead();
+ if (xselector.match((Object)cert))
+ {
+ certSet.add(cert);
+ }
+
+ }
+ catch (Exception e)
+ {
+
+ }
+ }
+
+ return certSet;
+ }
+
+ /**
+ * Can use the subject and serial and the subject and serialNumber of the
+ * certificate of the given of the X509CertStoreSelector. If a certificate
+ * for checking is given this has higher precedence.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the certificates in the LDAP
+ * directory.
+ * @param attrNames Attribute names in teh LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded certificates.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List certSubjectSerialSearch(X509CertStoreSelector xselector,
+ String[] attrs, String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ // TODO: support also subjectAltNames?
+ List list = new ArrayList();
+
+ String subject = null;
+ String serial = null;
+
+ subject = getSubjectAsString(xselector);
+
+ if (xselector.getSerialNumber() != null)
+ {
+ serial = xselector.getSerialNumber().toString();
+ }
+ if (xselector.getCertificate() != null)
+ {
+ subject = xselector.getCertificate().getSubjectX500Principal().getName("RFC1779");
+ serial = xselector.getCertificate().getSerialNumber().toString();
+ }
+
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (serial != null && params.getSearchForSerialNumberIn() != null)
+ {
+ attrValue = serial;
+ list.addAll(search(
+ splitString(params.getSearchForSerialNumberIn()),
+ attrValue, attrs));
+ }
+ if (serial == null && subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+
+
+ /**
+ * Can use the subject of the forward certificate of the set certificate
+ * pair or the subject of the forward
+ * {@link org.spongycastle.x509.X509CertStoreSelector} of the given
+ * selector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded certificate pairs.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List crossCertificatePairSubjectSearch(
+ X509CertPairStoreSelector xselector, String[] attrs,
+ String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ // search for subject
+ String subject = null;
+
+ if (xselector.getForwardSelector() != null)
+ {
+ subject = getSubjectAsString(xselector.getForwardSelector());
+ }
+ if (xselector.getCertPair() != null)
+ {
+ if (xselector.getCertPair().getForward() != null)
+ {
+ subject = xselector.getCertPair().getForward()
+ .getSubjectX500Principal().getName("RFC1779");
+ }
+ }
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Can use the entityName of the holder of the attribute certificate, the
+ * serialNumber of attribute certificate and the serialNumber of the
+ * associated certificate of the given of the X509AttributeCertSelector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded attribute certificates.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List attrCertSubjectSerialSearch(
+ X509AttributeCertStoreSelector xselector, String[] attrs,
+ String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ // search for serialNumber of associated cert,
+ // serialNumber of the attribute certificate or DN in the entityName
+ // of the holder
+
+ String subject = null;
+ String serial = null;
+
+ Collection serials = new HashSet();
+ Principal principals[] = null;
+ if (xselector.getHolder() != null)
+ {
+ // serialNumber of associated cert
+ if (xselector.getHolder().getSerialNumber() != null)
+ {
+ serials.add(xselector.getHolder().getSerialNumber()
+ .toString());
+ }
+ // DN in the entityName of the holder
+ if (xselector.getHolder().getEntityNames() != null)
+ {
+ principals = xselector.getHolder().getEntityNames();
+ }
+ }
+
+ if (xselector.getAttributeCert() != null)
+ {
+ if (xselector.getAttributeCert().getHolder().getEntityNames() != null)
+ {
+ principals = xselector.getAttributeCert().getHolder()
+ .getEntityNames();
+ }
+ // serialNumber of the attribute certificate
+ serials.add(xselector.getAttributeCert().getSerialNumber()
+ .toString());
+ }
+ if (principals != null)
+ {
+ // only first should be relevant
+ if (principals[0] instanceof X500Principal)
+ {
+ subject = ((X500Principal)principals[0])
+ .getName("RFC1779");
+ }
+ else
+ {
+ // strange ...
+ subject = principals[0].getName();
+ }
+ }
+ if (xselector.getSerialNumber() != null)
+ {
+ serials.add(xselector.getSerialNumber().toString());
+ }
+
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (serials.size() > 0
+ && params.getSearchForSerialNumberIn() != null)
+ {
+ Iterator it = serials.iterator();
+ while (it.hasNext())
+ {
+ serial = (String)it.next();
+ list.addAll(search(splitString(params.getSearchForSerialNumberIn()), serial, attrs));
+ }
+ }
+ if (serials.size() == 0 && subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Can use the issuer of the given of the X509CRLStoreSelector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param issuerAttributeNames Issuer attribute names (like "CN", "O", "OU") to use to search
+ * in the LDAP directory
+ * @return A list of found DER encoded CRLs.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List cRLIssuerSearch(X509CRLStoreSelector xselector,
+ String[] attrs, String attrNames[], String issuerAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ String issuer = null;
+ Collection issuers = new HashSet();
+/*
+ if (xselector.getIssuers() != null)
+ {
+ issuers.addAll(xselector.getIssuers());
+ }
+*/
+ if (xselector.getCertificateChecking() != null)
+ {
+ issuers.add(getCertificateIssuer(xselector.getCertificateChecking()));
+ }
+ if (xselector.getAttrCertificateChecking() != null)
+ {
+ Principal principals[] = xselector.getAttrCertificateChecking().getIssuer().getPrincipals();
+ for (int i=0; i<principals.length; i++)
+ {
+ if (principals[i] instanceof X500Principal)
+ {
+ issuers.add(principals[i]);
+ }
+ }
+ }
+ Iterator it = issuers.iterator();
+ while (it.hasNext())
+ {
+ issuer = ((X500Principal)it.next()).getName("RFC1779");
+ String attrValue = null;
+
+ for (int i = 0; i < issuerAttributeNames.length; i++)
+ {
+ attrValue = parseDN(issuer, issuerAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (issuer == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Returns a <code>List</code> of encodings of the certificates, attribute
+ * certificates, CRL or certificate pairs.
+ *
+ * @param attributeNames The attribute names to look for in the LDAP.
+ * @param attributeValue The value the attribute name must have.
+ * @param attrs The attributes in the LDAP which hold the certificate,
+ * attribute certificate, certificate pair or CRL in a found
+ * entry.
+ * @return A <code>List</code> of byte arrays with the encodings.
+ * @throws StoreException if an error occurs getting the results from the LDAP
+ * directory.
+ */
+ private List search(String attributeNames[], String attributeValue,
+ String[] attrs) throws StoreException
+ {
+ String filter = null;
+ if (attributeNames == null)
+ {
+ filter = null;
+ }
+ else
+ {
+ filter = "";
+ if (attributeValue.equals("**"))
+ {
+ attributeValue = "*";
+ }
+ for (int i = 0; i < attributeNames.length; i++)
+ {
+ filter += "(" + attributeNames[i] + "=" + attributeValue + ")";
+ }
+ filter = "(|" + filter + ")";
+ }
+ String filter2 = "";
+ for (int i = 0; i < attrs.length; i++)
+ {
+ filter2 += "(" + attrs[i] + "=*)";
+ }
+ filter2 = "(|" + filter2 + ")";
+
+ String filter3 = "(&" + filter + "" + filter2 + ")";
+ if (filter == null)
+ {
+ filter3 = filter2;
+ }
+ List list;
+ list = getFromCache(filter3);
+ if (list != null)
+ {
+ return list;
+ }
+ DirContext ctx = null;
+ list = new ArrayList();
+ try
+ {
+
+ ctx = connectLDAP();
+
+ SearchControls constraints = new SearchControls();
+ constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ constraints.setCountLimit(0);
+ constraints.setReturningAttributes(attrs);
+ NamingEnumeration results = ctx.search(params.getBaseDN(), filter3,
+ constraints);
+ while (results.hasMoreElements())
+ {
+ SearchResult sr = (SearchResult)results.next();
+ NamingEnumeration enumeration = ((Attribute)(sr
+ .getAttributes().getAll().next())).getAll();
+ while (enumeration.hasMore())
+ {
+ list.add(enumeration.next());
+ }
+ }
+ addToCache(filter3, list);
+ }
+ catch (NamingException e)
+ {
+ // skip exception, unfortunately if an attribute type is not
+ // supported an exception is thrown
+
+ }
+ finally
+ {
+ try
+ {
+ if (null != ctx)
+ {
+ ctx.close();
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ return list;
+ }
+
+ private Set createCRLs(List list, X509CRLStoreSelector xselector)
+ throws StoreException
+ {
+ Set crlSet = new HashSet();
+
+ X509CRLParser parser = new X509CRLParser();
+ Iterator it = list.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509CRL crl = (X509CRL)parser.engineRead();
+ if (xselector.match((Object)crl))
+ {
+ crlSet.add(crl);
+ }
+ }
+ catch (StreamParsingException e)
+ {
+
+ }
+ }
+
+ return crlSet;
+ }
+
+ private Set createCrossCertificatePairs(List list,
+ X509CertPairStoreSelector xselector) throws StoreException
+ {
+ Set certPairSet = new HashSet();
+
+ int i = 0;
+ while (i < list.size())
+ {
+ X509CertificatePair pair;
+ try
+ {
+ // first try to decode it as certificate pair
+ try
+ {
+ X509CertPairParser parser = new X509CertPairParser();
+ parser.engineInit(new ByteArrayInputStream(
+ (byte[])list.get(i)));
+ pair = (X509CertificatePair)parser.engineRead();
+ }
+ catch (StreamParsingException e)
+ {
+ // now try it to construct it the forward and reverse
+ // certificate
+ byte[] forward = (byte[])list.get(i);
+ byte[] reverse = (byte[])list.get(i + 1);
+ pair = new X509CertificatePair(new CertificatePair(
+ Certificate
+ .getInstance(new ASN1InputStream(
+ forward).readObject()),
+ Certificate
+ .getInstance(new ASN1InputStream(
+ reverse).readObject())));
+ i++;
+ }
+ if (xselector.match((Object)pair))
+ {
+ certPairSet.add(pair);
+ }
+ }
+ catch (CertificateParsingException e)
+ {
+ // try next
+ }
+ catch (IOException e)
+ {
+ // try next
+ }
+ i++;
+ }
+
+ return certPairSet;
+ }
+
+ private Set createAttributeCertificates(List list,
+ X509AttributeCertStoreSelector xselector) throws StoreException
+ {
+ Set certSet = new HashSet();
+
+ Iterator it = list.iterator();
+ X509AttrCertParser parser = new X509AttrCertParser();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509AttributeCertificate cert = (X509AttributeCertificate)parser
+ .engineRead();
+ if (xselector.match((Object)cert))
+ {
+ certSet.add(cert);
+ }
+ }
+ catch (StreamParsingException e)
+ {
+
+ }
+ }
+
+ return certSet;
+ }
+
+ /**
+ * Returns the CRLs for issued certificates for other CAs matching the given
+ * selector. <br>
+ * The authorityRevocationList attribute includes revocation information
+ * regarding certificates issued to other CAs.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs
+ * @throws StoreException
+ */
+ public Collection getAuthorityRevocationLists(X509CRLStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getAuthorityRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAuthorityRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAuthorityRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the revocation list for revoked attribute certificates.
+ * <p/>
+ * The attributeCertificateRevocationList holds a list of attribute
+ * certificates that have been revoked.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getAttributeCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params
+ .getAttributeCertificateRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeCertificateRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAttributeCertificateRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the revocation list for revoked attribute certificates for an
+ * attribute authority
+ * <p/>
+ * The attributeAuthorityList holds a list of AA certificates that have been
+ * revoked.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs
+ * @throws StoreException
+ */
+ public Collection getAttributeAuthorityRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeAuthorityRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeAuthorityRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAttributeAuthorityRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns cross certificate pairs.
+ *
+ * @param selector The selector to use to find the cross certificates.
+ * @return A possible empty collection with {@link X509CertificatePair}s
+ * @throws StoreException
+ */
+ public Collection getCrossCertificatePairs(
+ X509CertPairStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getCrossCertificateAttribute());
+ String attrNames[] = splitString(params.getLdapCrossCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getCrossCertificateSubjectAttributeName());
+ List list = crossCertificatePairSubjectSearch(selector, attrs,
+ attrNames, subjectAttributeNames);
+ Set resultSet = createCrossCertificatePairs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptyCertselector = new X509CertStoreSelector();
+ X509CertPairStoreSelector emptySelector = new X509CertPairStoreSelector();
+
+ emptySelector.setForwardSelector(emptyCertselector);
+ emptySelector.setReverseSelector(emptyCertselector);
+ list = crossCertificatePairSubjectSearch(emptySelector, attrs,
+ attrNames, subjectAttributeNames);
+ resultSet.addAll(createCrossCertificatePairs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns end certificates.
+ * <p/>
+ * The attributeDescriptorCertificate is self signed by a source of
+ * authority and holds a description of the privilege and its delegation
+ * rules.
+ *
+ * @param selector The selector to find the certificates.
+ * @return A possible empty collection with certificates.
+ * @throws StoreException
+ */
+ public Collection getUserCertificates(X509CertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getUserCertificateAttribute());
+ String attrNames[] = splitString(params.getLdapUserCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getUserCertificateSubjectAttributeName());
+
+ List list = certSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createCerts(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptySelector = new X509CertStoreSelector();
+ list = certSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createCerts(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns attribute certificates for an attribute authority
+ * <p/>
+ * The aAcertificate holds the privileges of an attribute authority.
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAACertificates(X509AttributeCertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getAACertificateAttribute());
+ String attrNames[] = splitString(params.getLdapAACertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params.getAACertificateSubjectAttributeName());
+
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns an attribute certificate for an authority
+ * <p/>
+ * The attributeDescriptorCertificate is self signed by a source of
+ * authority and holds a description of the privilege and its delegation
+ * rules.
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAttributeDescriptorCertificates(
+ X509AttributeCertStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeDescriptorCertificateAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeDescriptorCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getAttributeDescriptorCertificateSubjectAttributeName());
+
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns CA certificates.
+ * <p/>
+ * The cACertificate attribute of a CA's directory entry shall be used to
+ * store self-issued certificates (if any) and certificates issued to this
+ * CA by CAs in the same realm as this CA.
+ *
+ * @param selector The selector to find the certificates.
+ * @return A possible empty collection with certificates.
+ * @throws StoreException
+ */
+ public Collection getCACertificates(X509CertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getCACertificateAttribute());
+ String attrNames[] = splitString(params.getLdapCACertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getCACertificateSubjectAttributeName());
+ List list = certSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createCerts(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptySelector = new X509CertStoreSelector();
+ list = certSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createCerts(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the delta revocation list for revoked certificates.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getDeltaCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getDeltaRevocationListAttribute());
+ String attrNames[] = splitString(params.getLdapDeltaRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getDeltaRevocationListIssuerAttributeName());
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns an attribute certificate for an user.
+ * <p/>
+ * The attributeCertificateAttribute holds the privileges of a user
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAttributeCertificateAttributes(
+ X509AttributeCertStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeCertificateAttributeAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeCertificateAttributeAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getAttributeCertificateAttributeSubjectAttributeName());
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns the certificate revocation lists for revoked certificates.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getCertificateRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapCertificateRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getCertificateRevocationListIssuerAttributeName());
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ private Map cacheMap = new HashMap(cacheSize);
+
+ private static int cacheSize = 32;
+
+ private static long lifeTime = 60 * 1000;
+
+ private synchronized void addToCache(String searchCriteria, List list)
+ {
+ Date now = new Date(System.currentTimeMillis());
+ List cacheEntry = new ArrayList();
+ cacheEntry.add(now);
+ cacheEntry.add(list);
+ if (cacheMap.containsKey(searchCriteria))
+ {
+ cacheMap.put(searchCriteria, cacheEntry);
+ }
+ else
+ {
+ if (cacheMap.size() >= cacheSize)
+ {
+ // replace oldest
+ Iterator it = cacheMap.entrySet().iterator();
+ long oldest = now.getTime();
+ Object replace = null;
+ while (it.hasNext())
+ {
+ Map.Entry entry = (Map.Entry)it.next();
+ long current = ((Date)((List)entry.getValue()).get(0))
+ .getTime();
+ if (current < oldest)
+ {
+ oldest = current;
+ replace = entry.getKey();
+ }
+ }
+ cacheMap.remove(replace);
+ }
+ cacheMap.put(searchCriteria, cacheEntry);
+ }
+ }
+
+ private List getFromCache(String searchCriteria)
+ {
+ List entry = (List)cacheMap.get(searchCriteria);
+ long now = System.currentTimeMillis();
+ if (entry != null)
+ {
+ // too old
+ if (((Date)entry.get(0)).getTime() < (now - lifeTime))
+ {
+ return null;
+ }
+ return (List)entry.get(1);
+ }
+ return null;
+ }
+
+ /*
+ * spilt string based on spaces
+ */
+ private String[] splitString(String str)
+ {
+ return str.split("\\s+");
+ }
+
+ private String getSubjectAsString(X509CertStoreSelector xselector)
+ {
+ try
+ {
+ byte[] encSubject = xselector.getSubjectAsBytes();
+ if (encSubject != null)
+ {
+ return new X500Principal(encSubject).getName("RFC1779");
+ }
+ }
+ catch (IOException e)
+ {
+ throw new StoreException("exception processing name: " + e.getMessage(), e);
+ }
+ return null;
+ }
+
+ private X500Principal getCertificateIssuer(X509Certificate cert)
+ {
+ return cert.getIssuerX500Principal();
+ }
+}
diff --git a/libraries/spongycastle/prov/src/main/resources/org/spongycastle/x509/CertPathReviewerMessages.properties b/libraries/spongycastle/prov/src/main/resources/org/spongycastle/x509/CertPathReviewerMessages.properties
new file mode 100644
index 000000000..6843d2c31
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/resources/org/spongycastle/x509/CertPathReviewerMessages.properties
@@ -0,0 +1,616 @@
+
+## constructor exceptions
+
+# cert path is empty
+CertPathReviewer.emptyCertPath.title = CertPath is empty
+CertPathReviewer.emptyCertPath.text = PKIXCertPathReviewer: the CertPath is empty.
+CertPathReviewer.emptyCertPath.summary = PKIXCertPathReviewer: the CertPath is empty.
+CertPathReviewer.emptyCertPath.details = PKIXCertPathReviewer: the CertPath is empty.
+
+## name constraints processing errors
+
+# cert DN is not in the permitted tree
+# {0} DN as String
+CertPathReviewer.notPermittedDN.title = Name constraint error: certificate DN is not permitted
+CertPathReviewer.notPermittedDN.text = Name constraint error: the certificate DN {0} is not permitted.
+CertPathReviewer.notPermittedDN.summary = Name constraint error: certificate DN is not permitted.
+CertPathReviewer.notPermittedDN.details = Name constraint checking error. The certificate DN {0} is not in the permitted set of DNs.
+
+# cert DN is in the excluded tree
+# {0} DN as String
+CertPathReviewer.excludedDN.title = Name constraint error: certificate DN is excluded
+CertPathReviewer.excludedDN.text = Name constraint error: The certificate DN {0} is excluded.
+CertPathReviewer.excludedDN.summary = Name constraint error: certificate DN is excluded.
+CertPathReviewer.excludedDN.details = Name constraint checking error. The certificate DN {0} is inside of the excluded set of DNs.
+
+# cert email is not in the permitted tree
+# {0} email address as String
+CertPathReviewer.notPermittedEmail.title = Name constraint error: not permitted email address
+CertPathReviewer.notPermittedEmail.text = Name constraint error: certificate contains the not permitted email address {0}.
+CertPathReviewer.notPermittedEmail.summary = Name constraint error: not permitted email address.
+CertPathReviewer.notPermittedEmail.details = Name constraint checking error. The certificate contains the email address {0} which is not in the permitted set of email addresses.
+
+# cert email is in the excluded tree
+# {0} email as String
+CertPathReviewer.excludedEmail.title = Name constraint error: excluded email address
+CertPathReviewer.excludedEmail.text = Name constraint error: certificate contains the excluded email address {0}.
+CertPathReviewer.excludedEmail.summary = Name constraint error: excluded email address.
+CertPathReviewer.excludedEmail.details = Name constraint checking error. The certificate contains the email address {0} which is in the excluded set of email addresses.
+
+# cert IP is not in the permitted tree
+# {0} ip address as String
+CertPathReviewer.notPermittedIP.title = Name constraint error: not permitted IP address
+CertPathReviewer.notPermittedIP.text = Name constraint error: certificate contains the not permitted IP address {0}.
+CertPathReviewer.notPermittedIP.summary = Name constraint error: not permitted IP address.
+CertPathReviewer.notPermittedIP.details = Name constraint checking error. The certificate contains the IP address {0} which is not in the permitted set of IP addresses.
+
+# cert ip is in the excluded tree
+# {0} ip address as String
+CertPathReviewer.excludedIP.title = Name constraint error: excluded IP address
+CertPathReviewer.excludedIP.text = Name constraint error: certificate contains the excluded IP address {0}.
+CertPathReviewer.excludedIP.summary = Name constraint error: excluded IP address.
+CertPathReviewer.excludedIP.details = Name constraint checking error. The certificate contains the IP address {0} which is in the excluded set of IP addresses.
+
+# error processing the name constraints extension
+CertPathReviewer.ncExtError.title = Name constraint checking failed
+CertPathReviewer.ncExtError.text = Name constraint checking failed: there was an error processing the name constraints extension of the certificate.
+CertPathReviewer.ncExtError.summary = Error processing the name constraints extension.
+CertPathReviewer.ncExtError.details = Name constraint checking failed: there was an error processing the name constraints extension of the certificate.
+
+# error processing the subject alternative name extension
+CertPathReviewer.subjAltNameExtError.title = Name constraint checking failed
+CertPathReviewer.subjAltNameExtError.text = Name constraint checking failed: there was an error processing the subject alternative name extension of the certificate.
+CertPathReviewer.subjAltNameExtError.summary = Error processing the subject alternative name extension.
+CertPathReviewer.subjAltNameExtError.details = Name constraint checking failed: there was an error processing the subject alternative name extension of the certificate.
+
+# exception extracting subject name when checking subtrees
+# {0} subject Principal
+CertPathReviewer.ncSubjectNameError.title = Name constraint checking failed
+CertPathReviewer.ncSubjectNameError.text = Name constraint checking failed: there was an exception extracting the DN from the certificate.
+CertPathReviewer.ncSubjectNameError.summary = Name constraint checking failed: exception extracting the DN.
+CertPathReviewer.ncSubjectNameError.details = Name constraint checking failed: there was an exception extracting the DN from the certificate.
+
+
+## path length errors
+
+# max path length extended
+CertPathReviewer.pathLenghtExtended.title = Maximum path length extended
+CertPathReviewer.pathLenghtExtended.text = Certificate path invalid: Maximum path length extended.
+CertPathReviewer.pathLenghtExtended.summary = Certificate path invalid: Maximum path length extended.
+CertPathReviewer.pathLenghtExtended.details = Certificate path invalid: Maximum path length extended.
+
+# error reading length constraint from basic constraint extension
+CertPathReviewer.processLengthConstError.title = Path length checking failed
+CertPathReviewer.processLengthConstError.text = Path length checking failed: there was an error processing the basic constraint extension of the certificate.
+CertPathReviewer.processLengthConstError.summary = Error processing the subject alternative name extension.
+CertPathReviewer.processLengthConstError.details = Path length checking failed: there was an error processing the basic constraint extension of the certificate.
+
+
+## path length notifications
+
+# total path length as defined in rfc 3280
+# {0} the path length as Integer
+CertPathReviewer.totalPathLength.title = Total path length
+CertPathReviewer.totalPathLength.text = The total path length without self-signed certificates is {0}.
+CertPathReviewer.totalPathLength.summary = The total path length without self-signed certificates is {0}.
+CertPathReviewer.totalPathLength.details = The total path length without self-signed certificates, as defined in RFC 3280, is {0}.
+
+
+## critical extensions errors
+
+# one unknown critical extension
+# {0} extension as String
+CertPathReviewer.unknownCriticalExt.title = Unknown critical extension
+CertPathReviewer.unknownCriticalExt.text = The certificate contains the unknown critical extension {0}.
+CertPathReviewer.unknownCriticalExt.summary = Unknown critical extension: {0}.
+CertPathReviewer.unknownCriticalExt.details = The certificate contains the unknown critical extension with the OID {0}.
+
+# more unknown critical extensions
+# {0} extensions as Set of Strings
+CertPathReviewer.unknownCriticalExts.title = Unknown critical extensions
+CertPathReviewer.unknownCriticalExts.text = The certificate contains two or more unknown critical extensions: {0}.
+CertPathReviewer.unknownCriticalExts.summary = Unknown critical extensions: {0}.
+CertPathReviewer.unknownCriticalExts.details = The certificate contains two or more unknown critical extensions with the OIDs: {0}.
+
+# error processing critical extension
+# {0} the message of the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.criticalExtensionError.title = Error processing a critical extension
+CertPathReviewer.criticalExtensionError.text = Error processing a critical extension. A {0} occurred.
+CertPathReviewer.criticalExtensionError.summary = Error processing a critical extension. A {0} occurred.
+CertPathReviewer.criticalExtensionError.details = Error processing a critical extension. A {0} occurred. Cause: {0}.
+
+# error initializing the certpath checkers
+# {0} the message of the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.certPathCheckerError.title = Checking critical extensions failed
+CertPathReviewer.certPathCheckerError.text = Checking critical extensions failed: there was a {2} initializing a CertPathChecker.
+CertPathReviewer.certPathCheckerError.summary = Checking critical extensions failed: {2} initializing a CertPathChecker
+CertPathReviewer.certPathCheckerError.details = Checking critical extensions failed: there was an {2} initializing a CertPathChecker. Cause: {0}
+
+
+## check signature errors
+
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.title = Root key with valid signature but no trust anchor
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.text = The certificate has a valid signature, but is no trust anchor
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.summary = The certificate has a valid signature, but is no trust anchor
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.details = The certificate has a valid signature, but is no trust anchor
+
+# trustanchor found, but certificate validation failed
+CertPathReviewer.trustButInvalidCert.title = Trust anchor found, but different public key
+CertPathReviewer.trustButInvalidCert.text = A trust anchor was found. But it has a different public key, than was used to issue the first certificate of the cert path.
+CertPathReviewer.trustButInvalidCert.summary = A trust anchor was found. But it has a different public key, than was used to issue the first certificate of the cert path.
+CertPathReviewer.trustButInvalidCert.details = A trust anchor was found. But it has a different public key, than was used to issue the first certificate of the cert path.
+
+# trustanchor - cannot extract issuer
+CertPathReviewer.trustAnchorIssuerError.title = Finding trust anchor failed
+CertPathReviewer.trustAnchorIssuerError.text = Finding trust anchor failed: cannot extract issuer from certificate.
+CertPathReviewer.trustAnchorIssuerError.summary = Finding trust anchor failed: cannot extract issuer from certificate.
+CertPathReviewer.trustAnchorIssuerError.details = Finding trust anchor failed: cannot extract issuer from certificate.
+
+# no trustanchor was found for the certificate path
+# {0} issuer of the root certificate of the path
+# {1} number of trusted root certificates (trustanchors) provided
+CertPathReviewer.noTrustAnchorFound.title = No trusted root certificate found
+CertPathReviewer.noTrustAnchorFound.text = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation. The name of the CA is "{0}".
+CertPathReviewer.noTrustAnchorFound.summary = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation.
+CertPathReviewer.noTrustAnchorFound.details = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation. The name of the CA is "{0}". The trusted-root-certificate store contains {1} CA(s).
+
+# conflicting trust anchors
+# {0} number of trustanchors found (Integer)
+# {1} the ca name
+CertPathReviewer.conflictingTrustAnchors.title = Corrupt trust root store
+CertPathReviewer.conflictingTrustAnchors.text = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+CertPathReviewer.conflictingTrustAnchors.summary = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+CertPathReviewer.conflictingTrustAnchors.details = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+
+# trustanchor DN is invalid
+# {0} DN of the Trustanchor
+CertPathReviewer.trustDNInvalid.title = DN of TrustAnchor is improperly specified
+CertPathReviewer.trustDNInvalid.text = The DN of the TrustAnchor is improperly specified: {0}.
+CertPathReviewer.trustDNInvalid.summary = The DN of the TrustAnchor is improperly specified.
+CertPathReviewer.trustDNInvalid.details = The DN of the TrustAnchor is improperly specified: {0}. It's not a valid X.500 name. See RFC 1779 or RFC 2253.
+
+# trustanchor public key algorithm error
+CertPathReviewer.trustPubKeyError.title = Error processing public key of the trust anchor
+CertPathReviewer.trustPubKeyError.text = Error processing public key of the trust anchor.
+CertPathReviewer.trustPubKeyError.summary = Error processing public key of the trust anchor.
+CertPathReviewer.trustPubKeyError.details = Error processing public key of the trust anchor. Could not extract the AlorithmIdentifier for the key.
+
+# can not verifiy signature: issuer public key unknown
+CertPathReviewer.NoIssuerPublicKey.title = Can not verify the certificate signature
+CertPathReviewer.NoIssuerPublicKey.text = Can not verify the certificate signature: Issuer public key is unknown.
+CertPathReviewer.NoIssuerPublicKey.summary = Can not verify the certificate signature: Issuer public key is unknown.
+CertPathReviewer.NoIssuerPublicKey.details = Can not verify the certificate signature: Issuer public key is unknown.
+
+# signature can not be verified
+# {0} message of the underlying exception (english)
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.signatureNotVerified.title = Certificate signature invalid
+CertPathReviewer.signatureNotVerified.text = The certificate signature is invalid. A {2} occurred.
+CertPathReviewer.signatureNotVerified.summary = The certificate signature is invalid.
+CertPathReviewer.signatureNotVerified.details = The certificate signature is invalid. A {2} occurred. Cause: {0}
+
+# certificate expired
+# {0} the date the certificate expired
+CertPathReviewer.certificateExpired.title = Certificate is expired
+CertPathReviewer.certificateExpired.text = Could not validate the certificate. Certificate expired on {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.summary = Certificate expired on {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.details = Could not validate the certificate. Certificate expired on {0,date} {0,time,full}.
+
+# certificate not yet valid
+# {0} the date from which on the certificate is valid
+CertPathReviewer.certificateNotYetValid.title = Certificate is not yet valid
+CertPathReviewer.certificateNotYetValid.text = Could not validate the certificate. Certificate is not valid until {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.summary = Certificate is not valid until {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.details = Could not validate the certificate. Certificate is not valid until {0,date} {0,time,full}.
+
+# certificate invalid issuer DN
+# {0} expected issuer DN as String
+# {1} found issuer DN as String
+CertPathReviewer.certWrongIssuer.title = Issuer of certificate not valid
+CertPathReviewer.certWrongIssuer.text = Issuer of certificate is not valid. Expected {0}, but found {1}.
+CertPathReviewer.certWrongIssuer.summary = Issuer of certificate is not valid.
+CertPathReviewer.certWrongIssuer.details = Issuer of certificate is not valid. Expected {0}, but found {1}.
+
+# intermediate certificate is no ca cert
+CertPathReviewer.noCACert.title = Certificate is no CA certificate
+CertPathReviewer.noCACert.text = Intermediate certificate is no CA certificate.
+CertPathReviewer.noCACert.summary = The certificate is no CA certificate.
+CertPathReviewer.noCACert.details = The certificate is no CA certificate but used as one.
+
+# cert laks basic constraints
+CertPathReviewer.noBasicConstraints.title = Certificate has no basic constraints
+CertPathReviewer.noBasicConstraints.text = Intermediate certificate has no basic constraints.
+CertPathReviewer.noBasicConstraints.summary = Intermediate certificate has no basic constraints.
+CertPathReviewer.noBasicConstraints.details = Intermediate certificate has no basic constraints.
+
+# error processing basic constraints
+CertPathReviewer.errorProcesingBC.title = Error processing the basic constraints extension
+CertPathReviewer.errorProcesingBC.text = There was an error while processing the basic constraints extension of this certificate.
+CertPathReviewer.errorProcesingBC.summary = Error processing the basic constraints extension.
+CertPathReviewer.errorProcesingBC.details = There was an error while processing the basic constraints extension of this certificate.
+
+# certificate not usable for signing certs
+CertPathReviewer.noCertSign.title = Key not usable for signing certificates
+CertPathReviewer.noCertSign.text = The key usage constraint does not allow the use of this certificate key for signing certificates.
+CertPathReviewer.noCertSign.summary = The certificate key can not be used for signing certificates.
+CertPathReviewer.noCertSign.details = The key usage constraint does not allow the use of this certificate key for signing certificates.
+
+# error processing public key
+CertPathReviewer.pubKeyError.title = Error processing public key
+CertPathReviewer.pubKeyError.text = Error processing public key of the certificate.
+CertPathReviewer.pubKeyError.summary = Error processing public key of the certificate.
+CertPathReviewer.pubKeyError.details = Error processing public key of the certificate. Could not extract the AlorithmIdentifier for the key.
+
+
+## check signatures notifications
+
+#
+# trust anchor has no keyusage certSign
+CertPathReviewer.trustKeyUsage.title = Trust anchor key usage
+CertPathReviewer.trustKeyUsage.text = The trust anchor is not alloed to sign certificates.
+CertPathReviewer.trustKeyUsage.summary = The trust anchor is not alloed to sign certificates.
+CertPathReviewer.trustKeyUsage.details = The trust anchor is not alloed to sign certificates.
+
+# certificate path validation date
+# {0} date for which the cert path is validated
+# {1} current date
+CertPathReviewer.certPathValidDate.title = Certificate path validation date
+CertPathReviewer.certPathValidDate.text = The certificate path was applied on {0,date} {0,time,full}. It was checked at {1,date} {1,time,full}.
+CertPathReviewer.certPathValidDate.summary = The certificate path was validated for {0,date} {0,time,full}. It was checked at {1,date} {1,time,full}.
+CertPathReviewer.certPathValidDate.details = The certificate path was validated for {0,date} {0,time,full}. It was checked at {1,date} {1,time,full}.
+
+
+## check policy errors
+
+# error processing certificate policy extension
+CertPathReviewer.policyExtError.title = Policy checking failed
+CertPathReviewer.policyExtError.text = Policy checking failed: there was an error processing the certificate policy extension.
+CertPathReviewer.policyExtError.summary = Error processing the certificate policy extension.
+CertPathReviewer.policyExtError.details = Policy checking failed: there was an error processing the certificate policy extension.
+
+# error processing policy constraints extension
+CertPathReviewer.policyConstExtError.title = Policy checking failed
+CertPathReviewer.policyConstExtError.text = Policy checking failed: there was an error processing the policy constraints extension.
+CertPathReviewer.policyConstExtError.summary = Error processing the policy constraints extension.
+CertPathReviewer.policyConstExtError.details = Policy checking failed: there was an error processing the policy constraints extension.
+
+# error processing policy mapping extension
+CertPathReviewer.policyMapExtError.title = Policy checking failed
+CertPathReviewer.policyMapExtError.text = Policy checking failed: there was an error processing the policy mapping extension.
+CertPathReviewer.policyMapExtError.summary = Error processing the policy mapping extension.
+CertPathReviewer.policyMapExtError.details = Policy checking failed: there was an error processing the policy mapping extension.
+
+# error processing inhibit any policy extension
+CertPathReviewer.policyInhibitExtError.title = Policy checking failed
+CertPathReviewer.policyInhibitExtError.text = Policy checking failed: there was an error processing the inhibit any policy extension.
+CertPathReviewer.policyInhibitExtError.summary = Error processing the inhibit any policy extension.
+CertPathReviewer.policyInhibitExtError.details = Policy checking failed: there was an error processing the inhibit any policy extension.
+
+# error building qualifier set
+CertPathReviewer.policyQualifierError.title = Policy checking failed
+CertPathReviewer.policyQualifierError.text = Policy checking failed: error building the policy qualifier set.
+CertPathReviewer.policyQualifierError.summary = Policy checking failed: error building the policy qualifier set.
+CertPathReviewer.policyQualifierError.details = Policy checking failed: error building the policy qualifier set.
+
+# no valid policy tree - explicit policy required
+CertPathReviewer.noValidPolicyTree.title = Policy checking failed
+CertPathReviewer.noValidPolicyTree.text = Policy checking failed: no valid policy tree found when one expected.
+CertPathReviewer.noValidPolicyTree.summary = Policy checking failed: no valid policy tree found when one expected.
+CertPathReviewer.noValidPolicyTree.details = Policy checking failed: no valid policy tree found when one expected.
+
+# expicit policy requested, but no policy available
+CertPathReviewer.explicitPolicy.title = Policy checking failed
+CertPathReviewer.explicitPolicy.text = Policy checking failed: explicit policy requested but no policy available.
+CertPathReviewer.explicitPolicy.summary = Policy checking failed: explicit policy requested but no policy available.
+CertPathReviewer.explicitPolicy.details = Policy checking failed: explicit policy requested but no policy available.
+
+# path processing failed on policy
+CertPathReviewer.invalidPolicy.title = Path processing failed on policy
+CertPathReviewer.invalidPolicy.text = Path processing failed on policy.
+CertPathReviewer.invalidPolicy.summary = Path processing failed on policy.
+CertPathReviewer.invalidPolicy.details = Path processing failed on policy.
+
+# invalid policy mapping
+CertPathReviewer.invalidPolicyMapping.title = Invalid policy mapping
+CertPathReviewer.invalidPolicyMapping.text = Certificate contains an invalid policy mapping.
+CertPathReviewer.invalidPolicyMapping.summary = Certificate contains an invalid policy mapping.
+CertPathReviewer.invalidPolicyMapping.details = Certificate contains a policy mapping including the value any policy which is invalid.
+
+## check CRL notifications
+
+# found local valid CRL
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localValidCRL.title = Found valid local CRL
+CertPathReviewer.localValidCRL.text = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localValidCRL.summary = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localValidCRL.details = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+
+
+# found matching CRL, but not valid
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localInvalidCRL.title = Local CRL outdated
+CertPathReviewer.localInvalidCRL.text = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localInvalidCRL.summary = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localInvalidCRL.details = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+
+# found a valid crl at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineValidCRL.title = Found valid CRL at CRL distribution point
+CertPathReviewer.onlineValidCRL.text = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineValidCRL.summary = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineValidCRL.details = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+
+# found an invalid CRL at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineInvalidCRL.title = Outdated CRL at CRL distribution point
+CertPathReviewer.onlineInvalidCRL.text = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineInvalidCRL.summary = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineInvalidCRL.details = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+
+#found a CRL at a crl distribution point, but issued by another CA
+# {0} issuer of the CRL
+# {1} expected issuer
+# {2} the url of the distribution point
+CertPathReviewer.onlineCRLWrongCA.title = CRL from wrong issuer at CRL distribution point
+CertPathReviewer.onlineCRLWrongCA.text = The CRL loaded from {2} has was issued by {0}, excpected {1}.
+CertPathReviewer.onlineCRLWrongCA.summary = The CRL loaded from {2} has a wrong issuer.
+CertPathReviewer.onlineCRLWrongCA.details = The CRL loaded from {2} has was issued by {0}, excpected {1}.
+
+# Certificate not revoked
+CertPathReviewer.notRevoked.title = Certificate not revoked
+CertPathReviewer.notRevoked.text = The certificate was not revoked.
+CertPathReviewer.notRevoked.summary = The certificate was not revoked.
+CertPathReviewer.notRevoked.details = The certificate was not revoked.
+
+# CRL found: certificate was revoked, but after the validationDate
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.revokedAfterValidation.title = Certificate was revoked after the validation date
+CertPathReviewer.revokedAfterValidation.text = The certificate was revoked after the validation date at {0,date} {0,time,full}. Reason: {1}.
+CertPathReviewer.revokedAfterValidation.summary = The certificate was revoked after the validation date at {0,date} {0,time,full}.
+CertPathReviewer.revokedAfterValidation.details = The certificate was revoked after the validation date at {0,date} {0,time,full}. Reason: {1}.
+
+# updated crl available
+# {0} date since when the update is available
+CertPathReviewer.crlUpdateAvailable.title = CRL update available
+CertPathReviewer.crlUpdateAvailable.text = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.summary = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.details = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+
+# crl distribution point url
+# {0} the crl distribution point url as String
+CertPathReviewer.crlDistPoint.title = CRL distribution point
+CertPathReviewer.crlDistPoint.text = A CRL can be obtained from: {0}.
+CertPathReviewer.crlDistPoint.summary = A CRL can be obtained from: {0}.
+CertPathReviewer.crlDistPoint.details = A CRL can be obtained from: {0}.
+
+# ocsp location
+# {0} the url on which the ocsp service can be found
+CertPathReviewer.ocspLocation.title = OCSP responder location
+CertPathReviewer.ocspLocation.text = OCSP responder location: {0}.
+CertPathReviewer.ocspLocation.summary = OCSP responder location: {0}.
+CertPathReviewer.ocspLocation.details = OCSP responder location: {0}.
+
+# unable to get crl from crl distribution point
+# {0} the url of the distribution point
+# {1} the message of the occurred exception
+# {2} the occurred exception
+# {3} the name of the exception
+CertPathReviewer.loadCrlDistPointError.title = Cannot load CRL from CRL distribution point
+CertPathReviewer.loadCrlDistPointError.text = Unable to load a CRL from: {0}. A {3} occurred.
+CertPathReviewer.loadCrlDistPointError.summary = Unable to load a CRL from: {0}. A {3} occurred.
+CertPathReviewer.loadCrlDistPointError.details = Unable to load a CRL from: {0}. A {3} occurred. Cause: {1}.
+
+# no crl found in certstores
+# {0} the issuers which we searched for
+# {1} list of crl issuer names that are found in the certstores
+# {2} number of crls in the certstores
+CertPathReviewer.noCrlInCertstore.title = No matching CRL found in local CRL store
+CertPathReviewer.noCrlInCertstore.text = No matching CRL was found in the provided local CRL store.
+CertPathReviewer.noCrlInCertstore.summary = No matching CRL was found in the provided local CRL store.
+CertPathReviewer.noCrlInCertstore.details = No matching CRL was found in the provided local CRL store. \
+No CRL was found for the selector "{0}". The {2} CRL(s) in the certstores are from "{1}".
+
+
+## check CRL exceptions
+
+# cannot extract issuer from certificate
+CertPathReviewer.crlIssuerException.title = CRL checking failed
+CertPathReviewer.crlIssuerException.text = CRL checking failed: cannot extract issuer from certificate.
+CertPathReviewer.crlIssuerException.summary = CRL checking failed: cannot extract issuer from certificate.
+CertPathReviewer.crlIssuerException.details = CRL checking failed: cannot extract issuer from certificate.
+
+# cannot extract crls
+# {0} message from the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.crlExtractionError.title = CRL checking failed
+CertPathReviewer.crlExtractionError.text = CRL checking failed: Cannot extract CRL from CertStore. There was a {2}.
+CertPathReviewer.crlExtractionError.summary = CRL checking failed: Cannot extract CRL from CertStore. There was a {2}.
+CertPathReviewer.crlExtractionError.details = CRL checking failed: Cannot extract CRL from CertStore. There was a {2}. Cause: {0}.
+
+# Issuer certificate key usage extension does not permit crl signing
+CertPathReviewer.noCrlSigningPermited.title = CRL checking failed
+CertPathReviewer.noCrlSigningPermited.text = CRL checking failed: issuer certificate does not permit CRL signing.
+CertPathReviewer.noCrlSigningPermited.summary = CRL checking failed: issuer certificate does not permit CRL signing.
+CertPathReviewer.noCrlSigningPermited.details = CRL checking failed: issuer certificate does not permit CRL signing.
+
+# can not verify crl: issuer public key unknown
+CertPathReviewer.crlNoIssuerPublicKey.title = CRL checking failed
+CertPathReviewer.crlNoIssuerPublicKey.text = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+CertPathReviewer.crlNoIssuerPublicKey.summary = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+CertPathReviewer.crlNoIssuerPublicKey.details = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+
+# crl verification failed
+CertPathReviewer.crlVerifyFailed.title = CRL checking failed
+CertPathReviewer.crlVerifyFailed.text = CRL checking failed: CRL signature is invalid.
+CertPathReviewer.crlVerifyFailed.summary = CRL checking failed: CRL signature is invalid.
+CertPathReviewer.crlVerifyFailed.details = CRL checking failed: CRL signature is invalid.
+
+# no valid CRL found
+CertPathReviewer.noValidCrlFound.title = CRL checking failed
+CertPathReviewer.noValidCrlFound.text = CRL checking failed: no valid CRL found.
+CertPathReviewer.noValidCrlFound.summary = CRL checking failed: no valid CRL found.
+CertPathReviewer.noValidCrlFound.details = CRL checking failed: no valid CRL found.
+
+# No base CRL for delta CRL
+CertPathReviewer.noBaseCRL.title = CRL checking failed
+CertPathReviewer.noBaseCRL.text = CRL checking failed: no base CRL found for delta CRL.
+CertPathReviewer.noBaseCRL.summary = CRL checking failed: no base CRL found for delta CRL.
+CertPathReviewer.noBaseCRL.details = CRL checking failed: no base CRL found for delta CRL.
+
+# certificate revoked
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.certRevoked.title = Certificate was revoked
+CertPathReviewer.certRevoked.text = The certificate was revoked at {0,date} {0,time,full}. Reason: {1}.
+CertPathReviewer.certRevoked.summary = The certificate was revoked at {0,date} {0,time,full}.
+CertPathReviewer.certRevoked.details = The certificate was revoked at {0,date} {0,time,full}. Reason: {1}.
+
+# error processing issuing distribution point extension
+CertPathReviewer.distrPtExtError.title = CRL checking failed
+CertPathReviewer.distrPtExtError.text = CRL checking failed: there was an error processing the issuing distribution point extension.
+CertPathReviewer.distrPtExtError.summary = Error processing the issuing distribution point extension.
+CertPathReviewer.distrPtExtError.details = CRL checking failed: there was an error processing the issuing distribution point extension.
+
+# error processing crl distribution points extension
+CertPathReviewer.crlDistPtExtError.title = CRL checking failed
+CertPathReviewer.crlDistPtExtError.text = CRL checking failed: there was an error processing the crl distribution points extension.
+CertPathReviewer.crlDistPtExtError.summary = Error processing the crl distribution points extension.
+CertPathReviewer.crlDistPtExtError.details = CRL checking failed: there was an error processing the crl distribution points extension.
+
+# error processing the authority info access extension
+CertPathReviewer.crlAuthInfoAccError.title = CRL checking failed
+CertPathReviewer.crlAuthInfoAccError.text = CRL checking failed: there was an error processing the authority info access extension.
+CertPathReviewer.crlAuthInfoAccError.summary = Error processing the authority info access extension.
+CertPathReviewer.crlAuthInfoAccError.details = CRL checking failed: there was an error processing the authority info access extension.
+
+# error processing delta crl indicator extension
+CertPathReviewer.deltaCrlExtError.title = CRL checking failed
+CertPathReviewer.deltaCrlExtError.text = CRL checking failed: there was an error processing the delta CRL indicator extension.
+CertPathReviewer.deltaCrlExtError.summary = Error processing the delta CRL indicator extension.
+CertPathReviewer.deltaCrlExtError.details = CRL checking failed: there was an error processing the delta CRL indicator extension.
+
+# error porcessing crl number extension
+CertPathReviewer.crlNbrExtError.title = CRL checking failed
+CertPathReviewer.crlNbrExtError.text = CRL checking failed: there was an error processing the CRL number extension.
+CertPathReviewer.crlNbrExtError.summary = Error processing the CRL number extension.
+CertPathReviewer.crlNbrExtError.details = CRL checking failed: there was an error processing the CRL number extension.
+
+# error processing crl reason code extension
+CertPathReviewer.crlReasonExtError.title = CRL checking failed
+CertPathReviewer.crlReasonExtError.text = CRL checking failed: there was an error processing the CRL reason code extension.
+CertPathReviewer.crlReasonExtError.summary = Error processing the CRL reason code extension.
+CertPathReviewer.crlReasonExtError.details = CRL checking failed: there was an error processing the CRL reason code extension.
+
+# error processing basic constraints extension
+CertPathReviewer.crlBCExtError.title = CRL checking failed
+CertPathReviewer.crlBCExtError.text = CRL checking failed: there was an error processing the basic constraints extension.
+CertPathReviewer.crlBCExtError.summary = Error processing the basic constraints extension.
+CertPathReviewer.crlBCExtError.details = CRL checking failed: there was an error processing the basic constraints extension.
+
+# CA Cert CRL only contains user certificates
+CertPathReviewer.crlOnlyUserCert.title = CRL checking failed
+CertPathReviewer.crlOnlyUserCert.text = CRL checking failed: CRL only contains user certificates.
+CertPathReviewer.crlOnlyUserCert.summary = CRL checking failed: CRL only contains user certificates.
+CertPathReviewer.crlOnlyUserCert.details = CRL checking failed: CRL for CA certificate only contains user certificates.
+
+# End CRL only contains CA certificates
+CertPathReviewer.crlOnlyCaCert.title = CRL checking failed
+CertPathReviewer.crlOnlyCaCert.text = CRL checking failed: CRL only contains CA certificates.
+CertPathReviewer.crlOnlyCaCert.summary = CRL checking failed: CRL only contains CA certificates.
+CertPathReviewer.crlOnlyCaCert.details = CRL checking failed: CRL for end certificate only contains CA certificates.
+
+# onlyContainsAttributeCerts boolean is asserted
+CertPathReviewer.crlOnlyAttrCert.title = CRL checking failed
+CertPathReviewer.crlOnlyAttrCert.text = CRL checking failed: CRL only contains attribute certificates.
+CertPathReviewer.crlOnlyAttrCert.summary = CRL checking failed: CRL only contains attribute certificates.
+CertPathReviewer.crlOnlyAttrCert.details = CRL checking failed: CRL only contains attribute certificates.
+
+
+## QcStatement notifications
+
+# unkown statement
+# {0} statement OID
+# {1} statement as ANS1Sequence
+CertPathReviewer.QcUnknownStatement.title = Unknown statement in QcStatement extension
+CertPathReviewer.QcUnknownStatement.text = Unknown statement in QcStatement extension: OID = {0}
+CertPathReviewer.QcUnknownStatement.summary = Unknown statement in QcStatement extension: OID = {0}
+CertPathReviewer.QcUnknownStatement.details = Unknown statement in QcStatement extension: OID = {0}, statement = {1}
+
+# QcLimitValue Alpha currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueAlpha.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueAlpha.text = This certificate has a limit for the transaction value: {1,number, ###,###,###,##0.00#} {0}.
+CertPathReviewer.QcLimitValueAlpha.summary = Transaction value limit: {1,number, ###,###,###,##0.00#} {0}.
+CertPathReviewer.QcLimitValueAlpha.details = This certificate has a limitation on the value of transaction for which this certificate can be used to the specified amount, according to the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. The limit for this certificate is {1,number, ###,###,###,##0.00#} {0}.
+
+# QcLimitValue Numeric currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueNum.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueNum.text = This certificate has a limit for the transaction value: {1,number, ###,###,###,##0.00#} of currency {0} (See RFC 4217 for currency codes).
+CertPathReviewer.QcLimitValueNum.summary = Transaction value limit: {1,number, ###,###,###,##0.00#} of currency {0} (See RFC 4217 for currency codes).
+CertPathReviewer.QcLimitValueNum.details = This certificate has a limitation on the value of transaction for which this certificate can be used to the specified amount, according to the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. The limit for this certificate is {1,number, ###,###,###,##0.00#} of currency {0} (See RFC 4217 for currency codes).
+
+# QcSSCD
+CertPathReviewer.QcSSCD.title = QcSSCD Statement
+CertPathReviewer.QcSSCD.text = (SSCD) The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+CertPathReviewer.QcSSCD.summary = (SSCD) The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+CertPathReviewer.QcSSCD.details = (SSCD) The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+
+# QcEuCompliance
+CertPathReviewer.QcEuCompliance.title = Qualified Certificate
+CertPathReviewer.QcEuCompliance.text = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+CertPathReviewer.QcEuCompliance.summary = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+CertPathReviewer.QcEuCompliance.details = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+
+## QcStatement errors
+
+# error processing the QcStatement extension
+CertPathReviewer.QcStatementExtError.title = Error processing the qc statements extension
+CertPathReviewer.QcStatementExtError.text = Error processing the qc statements extension.
+CertPathReviewer.QcStatementExtError.summary = Error processing the qc statements extension.
+CertPathReviewer.QcStatementExtError.details = Error processing the qc statements extension.
+
+## unknown/generic errors
+CertPathReviewer.unknown.title = Unexpected Error
+CertPathReviewer.unknown.text = Unexpected Error {0}
+CertPathReviewer.unknown.summary = Unexpected Error
+CertPathReviewer.unknown.details = Unexpected Error {0}
+
+#
+# crl reasons
+#
+unspecified = Unspecified
+keyCompromise = Key Compromise
+cACompromise = CA Compromise
+affiliationChanged = Affiliation Changed
+superseded = Superseded
+cessationOfOperation = Cessation of Operation
+certificateHold = Certificate Hold
+unknown = Unknown
+removeFromCRL = Remove from CRL
+privilegeWithdrawn = Privilege Withdrawn
+aACompromise = AA Compromise
+
+#
+#
+#
+missingIssuer = The missing certificate was issued by
+missingSerial = with the serial number
+ \ No newline at end of file
diff --git a/libraries/spongycastle/prov/src/main/resources/org/spongycastle/x509/CertPathReviewerMessages_de.properties b/libraries/spongycastle/prov/src/main/resources/org/spongycastle/x509/CertPathReviewerMessages_de.properties
new file mode 100644
index 000000000..b9398ea94
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/resources/org/spongycastle/x509/CertPathReviewerMessages_de.properties
@@ -0,0 +1,621 @@
+
+## constructor exceptions
+
+# cert path is empty
+CertPathReviewer.emptyCertPath.title = Zertifizierungspfad ist leer
+CertPathReviewer.emptyCertPath.text = PKIXCertPathReviewer: der Zertifizierungspfad ist leer.
+CertPathReviewer.emptyCertPath.summary = PKIXCertPathReviewer: der Zertifizierungspfad ist leer.
+CertPathReviewer.emptyCertPath.details = PKIXCertPathReviewer: der Zertifizierungspfad ist leer.
+
+## name constraints processing errors
+
+# cert DN is not in the permitted tree
+# {0} DN as String
+CertPathReviewer.notPermittedDN.title = Fehler bei der Namensbeschränkung: Zertifikats DN ist nicht erlaubt
+CertPathReviewer.notPermittedDN.text = Fehler bei der Namensbeschränkung: Der Zertifikats DN {0} ist nicht erlaubt.
+CertPathReviewer.notPermittedDN.summary = Fehler bei der Namensbeschränkung: Der Zertifikats DN ist nicht erlaubt.
+CertPathReviewer.notPermittedDN.details = Fehler bei der Namensbeschränkung: Der Zertifikats DN {0} ist nicht im Set der erlaubten DNs.
+
+# cert DN is in the excluded tree
+# {0} DN as String
+CertPathReviewer.excludedDN.title = Fehler bei der Namensbeschränkung: Zertifikats DN ist ausgeschlossen
+CertPathReviewer.excludedDN.text = Fehler bei der Namensbeschränkung: Der Zertifikats DN {0} ist ausgeschlossen.
+CertPathReviewer.excludedDN.summary = Fehler bei der Namensbeschränkung: Der Zertifikats DN ist ausgeschlossen
+CertPathReviewer.excludedDN.details = Fehler bei der Namensbeschränkung: Der Zertifikats DN ist {0} is innerhalb des Sets von ausgeschlossenen DNs.
+
+# cert email is not in the permitted tree
+# {0} email address as String
+CertPathReviewer.notPermittedEmail.title = Fehler bei der Namensbeschränkung: nicht erlaubte Email Addresse
+CertPathReviewer.notPermittedEmail.text = Fehler bei der Namensbeschränkung: Das Zertifikat enthält die nicht erlaubte Email Addresse {0}.
+CertPathReviewer.notPermittedEmail.summary = Fehler bei der Namensbeschränkung: Die Email Addresse ist nicht erlaubt.
+CertPathReviewer.notPermittedEmail.details = Fehler bei der Namensbeschränkung: Das Zertifikat enthält die Email Addresse {0}, welche nicht im Set der erlaubten Email Addressen ist.
+
+# cert email is in the excluded tree
+# {0} email as String
+CertPathReviewer.excludedEmail.title = Fehler bei der Namensbeschränkung: Email Addresse ausgeschlossen
+CertPathReviewer.excludedEmail.text = Fehler bei der Namensbeschränkung: Die Email Addresse {0} im Zertifikat ist ausgeschlossen.
+CertPathReviewer.excludedEmail.summary = Fehler bei der Namensbeschränkung: Die Email Addresse ist ausgeschlossen.
+CertPathReviewer.excludedEmail.details = Fehler bei der Namensbeschränkung: Das Zertifikat enthält die Email Addresse {0}, welche im Set der ausgeschlossenen Email Addressen ist.
+
+# cert IP is not in the permitted tree
+# {0} ip address as String
+CertPathReviewer.notPermittedIP.title = Fehler bei der Namensbeschränkung: nicht erlaubte IP Addresse
+CertPathReviewer.notPermittedIP.text = Fehler bei der Namensbeschränkung: Das Zertifikat enthält die nicht erlaubte IP Addresse {0}.
+CertPathReviewer.notPermittedIP.summary = Fehler bei der Namensbeschränkung: Die IP Addresse ist nicht erlaubt.
+CertPathReviewer.notPermittedIP.details = Fehler bei der Namensbeschränkung: Das Zertifikat enthält die IP Addresse {0}, welche nicht im Set der erlaubten IP Addressen ist.
+
+# cert ip is in the excluded tree
+# {0} ip address as String
+CertPathReviewer.excludedIP.title = Fehler bei der Namensbeschränkung: Ausgeschlossene IP Addresse
+CertPathReviewer.excludedIP.text = Fehler bei der Namensbeschränkung: Das Zertifikat enhält die ausgeschlossene IP Addresse {0}.
+CertPathReviewer.excludedIP.summary = Fehler bei der Namensbeschränkung: Die IP Addresse im Zertifikat ist ausgeschlossen.
+CertPathReviewer.excludedIP.details = Fehler bei der Namensbeschränkung: Das Zertifikat enthält die IP Addresse {0}, welche im Set der ausgeschlossenen IP Addressen ist.
+
+# error processing the name constraints extension
+CertPathReviewer.ncExtError.title = Prüfen der Namensbeschränkungen fehlgeschlagen
+CertPathReviewer.ncExtError.text = Prüfen der Namensbeschränkungen fehlgeschlagen: Es gab Fehler bei der Verarbeitung der Name Constraints Erweiterung des Zertifikats.
+CertPathReviewer.ncExtError.summary = Prüfen der Namensbeschränkungen fehlgeschlagen: Fehler bei der Verarbeitung der Name Constraints Erweiterung.
+CertPathReviewer.ncExtError.details = Prüfen der Namensbeschränkungen fehlgeschlagen: Es gab Fehler bei der Verarbeitung der Name Constraints Erweiterung des Zertifikats.
+
+# error processing the subject alternative name extension
+CertPathReviewer.subjAltNameExtError.title = Prüfen der Namensbeschränkungen fehlgeschlagen
+CertPathReviewer.subjAltNameExtError.text = Prüfen der Namensbeschränkungen fehlgeschlagen: Es gab Fehler bei der Verarbeitung der Subject Alternative Name Erweiterung des Zertifikats.
+CertPathReviewer.subjAltNameExtError.summary = Prüfen der Namensbeschränkungen fehlgeschlagen: Fehler bei der Verarbeitung der Subject Alternative Name Erweiterung.
+CertPathReviewer.subjAltNameExtError.details = Prüfen der Namensbeschränkungen fehlgeschlagen: Es gab Fehler bei der Verarbeitung der Subject Alternative Name Erweiterung des Zertifikats.
+
+# exception extracting subject name when checking subtrees
+# {0} subject Principal
+CertPathReviewer.ncSubjectNameError.title = Prüfen der Namensbeschränkungen fehlgeschlagen
+CertPathReviewer.ncSubjectNameError.text = Prüfen der Namensbeschränkungen fehlgeschlagen: Es gab einen Fehler beim auslesen des DN des Zertifikats.
+CertPathReviewer.ncSubjectNameError.summary = Prüfen der Namensbeschränkungen fehlgeschlagen: Fehler beim auslesen des DNs.
+CertPathReviewer.ncSubjectNameError.details = Prüfen der Namensbeschränkungen fehlgeschlagen: Es gab einen Fehler beim auslesen des DN des Zertifikats.
+
+
+## path length errors
+
+# max path length extended
+CertPathReviewer.pathLenghtExtended.title = Maximale Pfadlänge überschritten
+CertPathReviewer.pathLenghtExtended.text = Zertifizierungspfad ungültig: die Maximale Pfadlänge ist überschritten.
+CertPathReviewer.pathLenghtExtended.summary = Zertifizierungspfad ungültig: die Maximale Pfadlänge ist überschritten.
+CertPathReviewer.pathLenghtExtended.details = Zertifizierungspfad ungültig: die Maximale Pfadlänge ist überschritten.
+
+# error reading length constraint from basic constraint extension
+CertPathReviewer.processLengthConstError.title = Prüfen der Pfadlänge fehlgeschlagen
+CertPathReviewer.processLengthConstError.text = Prüfen der Pfadlänge fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der subject alternative name Erweiterung des Zertifikats.
+CertPathReviewer.processLengthConstError.summary = Fehler bei der Verarbeitung der subject alternative name Erweiterung.
+CertPathReviewer.processLengthConstError.details = Prüfen der Pfadlänge fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der subject alternative name Erweiterung des Zertifikats.
+
+
+## path length notifications
+
+# total path length as defined in rfc 3280
+# {0} the path length as Integer
+CertPathReviewer.totalPathLength.title = Totale Pfadlänge
+CertPathReviewer.totalPathLength.text = Die totale Pfadlänge ohne self-signed Zertifikate ist {0}.
+CertPathReviewer.totalPathLength.summary = Die totale Pfadlänge ohne self-signed Zertifikate ist {0}.
+CertPathReviewer.totalPathLength.details = Die totale Pfadlänge ohne self-signed Zertifikate, wie beschrieben in RFC 3280, ist {0}.
+
+
+## critical extensions errors
+
+# one unknown critical extension
+# {0} extension as String
+CertPathReviewer.unknownCriticalExt.title = Unbekannte kritische Erweiterung
+CertPathReviewer.unknownCriticalExt.text = Das Zertifikat enhält eine unbekannte kritische Erweiterung mit der OID {0}.
+CertPathReviewer.unknownCriticalExt.summary = Unbekannte kritische Erweiterung: {0}.
+CertPathReviewer.unknownCriticalExt.details = Das Zertifikat enhält eine unbekannte kritische Erweiterung mit der OID {0}.
+
+# more unknown critical extensions
+# {0} extensions as Set of Strings
+CertPathReviewer.unknownCriticalExts.title = Unbekannte kritische Erweiterung
+CertPathReviewer.unknownCriticalExts.text = Das Zertifikat enhält zwei oder mehr unbekannte kritische Erweiterungen mit den OIDs {0}.
+CertPathReviewer.unknownCriticalExts.summary = Unbekannte kritische Erweiterungen: {0}.
+CertPathReviewer.unknownCriticalExts.details = Das Zertifikat enhält zwei oder mehr unbekannte kritische Erweiterungen mit den OIDs {0}.
+
+# error processing critical extension
+# {0} the message of the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.criticalExtensionError.title = Fehler bei der Verarbeitung einer kritischen Erweiterung
+CertPathReviewer.criticalExtensionError.text = Fehler bei der Verarbeitung einer kritischen Erweiterung. Es gab eine {2}.
+CertPathReviewer.criticalExtensionError.summary = Fehler bei der Verarbeitung einer kritischen Erweiterung. Es gab eine {2}.
+CertPathReviewer.criticalExtensionError.details = Fehler bei der Verarbeitung einer kritischen Erweiterung. Es gab eine {2}. Grund: {0}.
+
+# error initializing the certpath checkers
+# {0} the message of the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.certPathCheckerError.title = Prüfen der kritischen Erweiterungen fehlgeschlagen
+CertPathReviewer.certPathCheckerError.text = Prüfen der kritischen Erweiterungen fehlgeschlagen: Es gab eine {2} bei der Initialisierung eines CertPathChecker.
+CertPathReviewer.certPathCheckerError.summary = Prüfen der kritischen Erweiterungen fehlgeschlagen: {2} bei der Initialisierung eines CertPathChecker.
+CertPathReviewer.certPathCheckerError.details = Prüfen der kritischen Erweiterungen fehlgeschlagen: Es gab eine {2} bei der Initialisierung eines CertPathChecker. Grund: {0}
+
+
+## check signature errors
+
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.title = rootKeyIsValidButNotATrustAnchor
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.text = Das Zertifikat hat eine gültige Signatur, ist aber kein vertrauenswürdiges Root Zertifikat.
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.summary = Das Zertifikat hat eine gültige Signatur, ist aber kein vertrauenswürdiges Root Zertifikat.
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.details = Das Zertifikat hat eine gültige Signatur, ist aber kein vertrauenswürdiges Root Zertifikat.
+
+# trustanchor found, but certificate validation failed
+CertPathReviewer.trustButInvalidCert.title = Vertrauenswürdiges Root Zertifikat invalid
+CertPathReviewer.trustButInvalidCert.text = Ein Root Zertifikat wurde gefunden. Es hat aber einen anderen öffentlichen Schlüssel als verwendet wurde um das erste Zertifikat des Zertifizierungspfades zu signieren.
+CertPathReviewer.trustButInvalidCert.summary = Ein Root Zertifikat wurde gefunden. Es hat aber einen anderen öffentlichen Schlüssel als verwendet wurde um das erste Zertifikat des Zertifizierungspfades zu signieren.
+CertPathReviewer.trustButInvalidCert.details = Ein Root Zertifikat wurde gefunden. Es hat aber einen anderen öffentlichen Schlüssel als verwendet wurde um das erste Zertifikat des Zertifizierungspfades zu signieren.
+
+# trustanchor - cannot extract issuer
+CertPathReviewer.trustAnchorIssuerError.title = Kann kein vertrauenswürdiges Root Zertifikat finden
+CertPathReviewer.trustAnchorIssuerError.text = Kann kein vertrauenswürdiges Root Zertifikat finden: Der Herausgeber vom Zertifikat kann nicht auslesen werden.
+CertPathReviewer.trustAnchorIssuerError.summary = Kann kein vertrauenswürdiges Root Zertifikat finden: Der Herausgeber vom Zertifikat kann nicht auslesen werden.
+CertPathReviewer.trustAnchorIssuerError.details = Kann kein vertrauenswürdiges Root Zertifikat finden: Der Herausgeber vom Zertifikat kann nicht auslesen werden.
+
+# no trustanchor was found for the certificate path
+# {0} issuer of the root certificate of the path
+# {1} number of trusted root certificates (trustanchors) provided
+CertPathReviewer.noTrustAnchorFound.title = Kein vertrauenswürdiges Root Zertifikat gefunden
+CertPathReviewer.noTrustAnchorFound.text = Das Root Zertifikat der Zertifizierungspfads wurde nicht von einer vertrauenswürdigen CA ausgestellt. Der Name der CA ist "{0}".
+CertPathReviewer.noTrustAnchorFound.summary = Das Root Zertifikat der Zertifizierungspfads wurde nicht von einer vertrauenswürdigen CA ausgestellt.
+CertPathReviewer.noTrustAnchorFound.details = Das Root Zertifikat der Zertifizierungspfads wurde nicht von einer vertrauenswürdigen CA ausgestellt. Der Name der CA ist "{0}". Der Root-Zertifikat-Speicher enthält {1} CA(s).
+
+# conflicting trust anchors
+# {0} number of trustanchors found (Integer)
+# {1} the ca name
+CertPathReviewer.conflictingTrustAnchors.title = Korrupter Root-Zertifikat-Speicher
+CertPathReviewer.conflictingTrustAnchors.text = Warnung: Es sind {0} öffentliche Schlüssel für die CA "{1}" im Root-Zertifikat-Speicher vorhanden - bitte prüfen Sie mit der CA welches der richtige Schlüssel ist.
+CertPathReviewer.conflictingTrustAnchors.summary = Warnung: Es sind {0} öffentliche Schlüssel für die CA "{1}" im Root-Zertifikat-Speicher vorhanden - bitte prüfen Sie mit der CA welches der richtige Schlüssel ist.
+CertPathReviewer.conflictingTrustAnchors.details = Warnung: Es sind {0} öffentliche Schlüssel für die CA "{1}" im Root-Zertifikat-Speicher vorhanden - bitte prüfen Sie mit der CA welches der richtige Schlüssel ist.
+
+# trustanchor DN is invalid
+# {0} DN of the Trustanchor
+CertPathReviewer.trustDNInvalid.title = DN des vertrauenswürdigen Root Zertifikats mit falschem Format.
+CertPathReviewer.trustDNInvalid.text = Der DN des vertrauenswürdigen Root Zertifikats hat ein falsches Format: {0}.
+CertPathReviewer.trustDNInvalid.summary = Der DN des vertrauenswürdigen Root Zertifikats hat ein falsches Format: {0}.
+CertPathReviewer.trustDNInvalid.details = Der DN des vertrauenswürdigen Root Zertifikats hat ein falsches Format: {0}. Es ist kein gültiger X.500 Name. Siehe RFC 1779 oder RFC 2253.
+
+# trustanchor public key algorithm error
+CertPathReviewer.trustPubKeyError.title = Fehler bei der Verarbeitung des öffentlichen Schlüssels der vertrauenswürdigen Root Zertifikats
+CertPathReviewer.trustPubKeyError.text = Fehler bei der Verarbeitung des öffentlichen Schlüssels der vertrauenswürdigen Root Zertifikats.
+CertPathReviewer.trustPubKeyError.summary = Fehler bei der Verarbeitung des öffentlichen Schlüssels der vertrauenswürdigen Root Zertifikats.
+CertPathReviewer.trustPubKeyError.details = Fehler bei der Verarbeitung des öffentlichen Schlüssels der vertrauenswürdigen Root Zertifikats. Der AlorithmIdentifier vom Schlüssel kann nicht ausgelesen werden.
+
+# can not verifiy signature: issuer public key unknown
+CertPathReviewer.NoIssuerPublicKey.title = Zertifikats Signatur kann nicht geprüft werden
+CertPathReviewer.NoIssuerPublicKey.text = Die Zertifikats Signatur kann nicht geprüft werden: Der öffentliche Schlüssel des Herausgebers ist unbekannt.
+CertPathReviewer.NoIssuerPublicKey.summary = Die Zertifikats Signatur kann nicht geprüft werden: Der öffentliche Schlüssel des Herausgebers ist unbekannt.
+CertPathReviewer.NoIssuerPublicKey.details = Die Zertifikats Signatur kann nicht geprüft werden: Der öffentliche Schlüssel des Herausgebers ist unbekannt.
+
+# signature can not be verified
+# {0} message of the underlying exception (english)
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.signatureNotVerified.title = Zertifikats Signatur ist ungültig
+CertPathReviewer.signatureNotVerified.text = Die Zertifikats Signatur ist ungültig. Es gab eine {2}.
+CertPathReviewer.signatureNotVerified.summary = Die Zertifikats Signatur ist ungültig.
+CertPathReviewer.signatureNotVerified.details = Die Zertifikats Signatur ist ungültig. Es gab eine {2}. Grund: {0}
+
+# certificate expired
+# {0} the date the certificate expired
+CertPathReviewer.certificateExpired.title = Zertifikat ist abgelaufen
+CertPathReviewer.certificateExpired.text = Das Zertifikat ist ungültig. Es ist am {0,date} {0,time,full} abgelaufen.
+CertPathReviewer.certificateExpired.summary = Das Zertifikat ist abgelaufen am {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.details = Das Zertifikat ist ungültig. Es ist am {0,date} {0,time,full} abgelaufen.
+
+# certificate not yet valid
+# {0} the date from which on the certificate is valid
+CertPathReviewer.certificateNotYetValid.title = Das Zertifikat ist noch nicht gültig
+CertPathReviewer.certificateNotYetValid.text = Das Zertifikat ist ungültig. Es ist erst gültig ab {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.summary = Das Zertifikat ist nicht gültig bis {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.details = Das Zertifikat ist ungültig. Es ist erst gültig ab {0,date} {0,time,full}.
+
+# certificate invalid issuer DN
+# {0} expected issuer DN as String
+# {1} found issuer DN as String
+CertPathReviewer.certWrongIssuer.title = Falscher Herausgeber
+CertPathReviewer.certWrongIssuer.text = Das Herausgeber des Zertifikats ist ungültig. Erwartet {0}, gefunden {1}.
+CertPathReviewer.certWrongIssuer.summary = Das Herausgeber des Zertifikats ist ungültig.
+CertPathReviewer.certWrongIssuer.details = Das Herausgeber des Zertifikats ist ungültig. Erwartet {0}, gefunden {1}.
+
+# intermediate certificate is no ca cert
+CertPathReviewer.noCACert.title = Zertifikat ist kein CA Zertifikat
+CertPathReviewer.noCACert.text = Das Zertifikat ist kein CA Zertifikat.
+CertPathReviewer.noCACert.summary = Das Zertifikat ist kein CA Zertifikat.
+CertPathReviewer.noCACert.details = Das Zertifikat ist kein CA Zertifikat, wird aber wie eines gebraucht.
+
+# cert laks basic constraints
+CertPathReviewer.noBasicConstraints.title = Zertifikat hat keine Basiseinschränkungen
+CertPathReviewer.noBasicConstraints.text = Das Zertifikat hat keine Basiseinschränkungen.
+CertPathReviewer.noBasicConstraints.summary = Das Zertifikat hat keine Basiseinschränkungen.
+CertPathReviewer.noBasicConstraints.details = Das Zertifikat hat keine Basiseinschränkungen.
+
+# error processing basic constraints
+CertPathReviewer.errorProcesingBC.title = Fehler bei der Verarbeitung der Basiseinschränkungen
+CertPathReviewer.errorProcesingBC.text = Es gab einen Fehler bei der Verarbeitung der Basiseinschränkungen des Zertifikats.
+CertPathReviewer.errorProcesingBC.summary = Fehler bei der Verarbeitung der Basiseinschränkungen
+CertPathReviewer.errorProcesingBC.details = Es gab einen Fehler bei der Verarbeitung der Basiseinschränkungen des Zertifikats.
+
+# certificate not usable for signing certs
+CertPathReviewer.noCertSign.title = Schlüssel nicht nutzbar für Zertifikatssignaturen
+CertPathReviewer.noCertSign.text = Der Schlüssel kann nicht zum Signieren von Zertifikaten verwendet werden.
+CertPathReviewer.noCertSign.summary = Der Schlüssel kann nicht zum Signieren von Zertifikaten verwendet werden.
+CertPathReviewer.noCertSign.details = Der Schlüssel kann nicht zum Signieren von Zertifikaten verwendet werden.
+
+# error processing public key
+CertPathReviewer.pubKeyError.title = Fehler bei der Verarbeitung des öffentlichen Schlüssels
+CertPathReviewer.pubKeyError.text = Fehler bei der Verarbeitung des öffentlichen Schlüssels des Zertifikats.
+CertPathReviewer.pubKeyError.summary = Fehler bei der Verarbeitung des öffentlichen Schlüssels des Zertifikats.
+CertPathReviewer.pubKeyError.details = Fehler bei der Verarbeitung des öffentlichen Schlüssels des Zertifikats. Der AlorithmIdentifier konnte nicht extrahiert werden.
+
+
+## check signatures notifications
+
+#
+# trust anchor has no keyusage certSign
+CertPathReviewer.trustKeyUsage.title = Root-Zertifikat Schlüsselverwendung
+CertPathReviewer.trustKeyUsage.text = Das Root-Zertifikat darf nicht zum Signieren von Zertifikaten verwendet werden.
+CertPathReviewer.trustKeyUsage.summary = Das Root-Zertifikat darf nicht zum Signieren von Zertifikaten verwendet werden.
+CertPathReviewer.trustKeyUsage.details = Das Root-Zertifikat darf nicht zum Signieren von Zertifikaten verwendet werden.
+
+# certificate path validation date
+# {0} date for which the cert path is validated
+# {1} current date
+CertPathReviewer.certPathValidDate.title = Datum der Zertifikatspfad Validierung
+CertPathReviewer.certPathValidDate.text = Der Zertifikatspfad wurde am {0,date} {0,time,full} angewendet. Er wurde am {1,date} {1,time,full} geprüft.
+CertPathReviewer.certPathValidDate.summary = Der Zertifikatspfad wurde am {0,date} {0,time,full} angewendet. Er wurde am {1,date} {1,time,full} geprüft.
+CertPathReviewer.certPathValidDate.details = Der Zertifikatspfad wurde am {0,date} {0,time,full} angewendet. Er wurde am {1,date} {1,time,full} geprüft.
+
+
+## check policy errors
+
+# error processing certificate policy extension
+CertPathReviewer.policyExtError.title = Prüfen der Policy fehlgeschlagen
+CertPathReviewer.policyExtError.text = Prüfen der Policy fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Policy Erweiterung.
+CertPathReviewer.policyExtError.summary = Fehler bei der Verarbeitung der Policy Erweiterung.
+CertPathReviewer.policyExtError.details = Prüfen der Policy fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Policy Erweiterung.
+
+# error processing policy constraints extension
+CertPathReviewer.policyConstExtError.title = Prüfen der Policy fehlgeschlagen
+CertPathReviewer.policyConstExtError.text = Prüfen der Policy fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Policy Constraints Erweiterung.
+CertPathReviewer.policyConstExtError.summary = Fehler bei der Verarbeitung der Policy Constraints Erweiterung.
+CertPathReviewer.policyConstExtError.details = Prüfen der Policy fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Policy Constraints Erweiterung.
+
+# error processing policy mapping extension
+CertPathReviewer.policyMapExtError.title = Prüfen der Policy fehlgeschlagen
+CertPathReviewer.policyMapExtError.text = Prüfen der Policy fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Policy Mapping Erweiterung.
+CertPathReviewer.policyMapExtError.summary = Fehler bei der Verarbeitung der Policy Mapping Erweiterung.
+CertPathReviewer.policyMapExtError.details = Prüfen der Policy fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Policy Mapping Erweiterung.
+
+# error processing inhibit any policy extension
+CertPathReviewer.policyInhibitExtError.title = Prüfen der Policy fehlgeschlagen
+CertPathReviewer.policyInhibitExtError.text = Prüfen der Policy fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Inhibit Any Policy Erweiterung.
+CertPathReviewer.policyInhibitExtError.summary = Fehler bei der Verarbeitung der Inhibit Any Policy Erweiterung.
+CertPathReviewer.policyInhibitExtError.details = Prüfen der Policy fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Inhibit Any Policy Erweiterung.
+
+# error building qualifier set
+CertPathReviewer.policyQualifierError.title = Prüfen der Policy fehlgeschlagen
+CertPathReviewer.policyQualifierError.text = Prüfen der Policy fehlgeschlagen: Fehler beim erstellen des Policy Qualifier Set.
+CertPathReviewer.policyQualifierError.summary = Prüfen der Policy fehlgeschlagen: Fehler beim erstellen des Policy Qualifier Set.
+CertPathReviewer.policyQualifierError.details = Prüfen der Policy fehlgeschlagen: Fehler beim erstellen des Policy Qualifier Set.
+
+# no valid policy tree - explicit policy required
+CertPathReviewer.noValidPolicyTree.title = Prüfen der Policy fehlgeschlagen
+CertPathReviewer.noValidPolicyTree.text = Prüfen der Policy fehlgeschlagen: Kein gültiger Policy Baum gefunden, als einer erwartet wurde.
+CertPathReviewer.noValidPolicyTree.summary = Prüfen der Policy fehlgeschlagen: Kein gültiger Policy Baum gefunden, als einer erwartet wurde.
+CertPathReviewer.noValidPolicyTree.details = Prüfen der Policy fehlgeschlagen: Kein gültiger Policy Baum gefunden, als einer erwartet wurde.
+
+# expicit policy requested, but no policy available
+CertPathReviewer.explicitPolicy.title = Prüfen der Policy fehlgeschlagen
+CertPathReviewer.explicitPolicy.text = Prüfen der Policy fehlgeschlagen: Policy verlang, aber keine Policy vorhanden.
+CertPathReviewer.explicitPolicy.summary = Prüfen der Policy fehlgeschlagen: Policy verlang, aber keine Policy vorhanden.
+CertPathReviewer.explicitPolicy.details = Prüfen der Policy fehlgeschlagen: Policy verlang, aber keine Policy vorhanden.
+
+# path processing failed on policy
+CertPathReviewer.invalidPolicy.title = Pfad Validierung wegen der Policy fehlgeschlagen
+CertPathReviewer.invalidPolicy.text = Pfad Validierung wegen der Policy fehlgeschlagen.
+CertPathReviewer.invalidPolicy.summary = Pfad Validierung wegen der Policy fehlgeschlagen.
+CertPathReviewer.invalidPolicy.details = Pfad Validierung wegen der Policy fehlgeschlagen.
+
+# invalid policy mapping
+CertPathReviewer.invalidPolicyMapping.title = Ungültiges Policy Mapping
+CertPathReviewer.invalidPolicyMapping.text = Das Zertifikat enthält ein Ungültiges Policy Mapping.
+CertPathReviewer.invalidPolicyMapping.summary = Das Zertifikat enthält ein Ungültiges Policy Mapping.
+CertPathReviewer.invalidPolicyMapping.details = Das Zertifikat enthält ein Ungültiges Policy Mapping, das den Wert Any Policy enthält.
+
+## check CRL notifications
+
+# found local valid CRL
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localValidCRL.title = Gültige Zertifikatssperrliste (CRL) gefunden
+CertPathReviewer.localValidCRL.text = Gültige Zertifikatssperrliste (CRL) im lokalen Speicher gefunden. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+CertPathReviewer.localValidCRL.summary = Gültige Zertifikatssperrliste (CRL) im lokalen Speicher gefunden. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+CertPathReviewer.localValidCRL.details = Gültige Zertifikatssperrliste (CRL) im lokalen Speicher gefunden. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+
+
+# found matching CRL, but not valid
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localInvalidCRL.title = Lokale Zertifikatssperrliste (CRL) veraltet
+CertPathReviewer.localInvalidCRL.text = Eine lokale Zertifikatssperrliste (CRL) wurde nicht genutzt, da sie veraltet ist. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+CertPathReviewer.localInvalidCRL.summary = Eine lokale Zertifikatssperrliste (CRL) wurde nicht genutzt, da sie veraltet ist. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+CertPathReviewer.localInvalidCRL.details = Eine lokale Zertifikatssperrliste (CRL) wurde nicht genutzt, da sie veraltet ist. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+
+# found a valid crl at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineValidCRL.title = Gültige Zertifikatssperrliste (CRL) von einem CDP
+CertPathReviewer.onlineValidCRL.text = Gültige Zertifikatssperrliste (CRL) gefunden von: {2}. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+CertPathReviewer.onlineValidCRL.summary = Gültige Zertifikatssperrliste (CRL) gefunden von: {2}. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+CertPathReviewer.onlineValidCRL.details = Gültige Zertifikatssperrliste (CRL) gefunden von: {2}. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+
+# found an invalid CRL at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineInvalidCRL.title = Veraltete Zertifikatssperrliste (CRL) von einem CDP
+CertPathReviewer.onlineInvalidCRL.text = Die Zertifikatssperrliste (CRL) von {2} ist veraltet. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+CertPathReviewer.onlineInvalidCRL.summary = Die Zertifikatssperrliste (CRL) von {2} ist veraltet. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+CertPathReviewer.onlineInvalidCRL.details = Die Zertifikatssperrliste (CRL) von {2} ist veraltet. Herausgegeben am {0,date}, nächstes Update am {1,date}.
+
+#found a CRL at a crl distribution point, but issued by another CA
+# {0} issuer of the CRL
+# {1} expected issuer
+# {2} the url of the distribution point
+CertPathReviewer.onlineCRLWrongCA.title = Zertifikatssperrliste (CRL) von CDP mit falschem Herausgeber
+CertPathReviewer.onlineCRLWrongCA.text = Die Zertifikatssperrliste (CRL) von {2} wurde von {0} herausgegeben, erwartet wurde {1}.
+CertPathReviewer.onlineCRLWrongCA.summary = Die Zertifikatssperrliste (CRL) von {2} hat einen falschen Herausgeber.
+CertPathReviewer.onlineCRLWrongCA.details = Die Zertifikatssperrliste (CRL) von {2} wurde von {0} herausgegeben, erwartet wurde {1}.
+
+# Certificate not revoked
+CertPathReviewer.notRevoked.title = Zertifikat nicht revoziert
+CertPathReviewer.notRevoked.text = Das Zertifikat ist nicht revoziert.
+CertPathReviewer.notRevoked.summary = Das Zertifikat ist nicht revoziert.
+CertPathReviewer.notRevoked.details = Das Zertifikat ist nicht revoziert.
+
+# CRL found: certificate was revoked, but after the validationDate
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.revokedAfterValidation.title = Zertifikat revoziert nach dem Validierungdatum
+CertPathReviewer.revokedAfterValidation.text = Das Zertifikat wurde nach dem Validierungdatum am {0,date} {0,time,full} revoziert. Grund: {1}.
+CertPathReviewer.revokedAfterValidation.summary = Das Zertifikat wurde nach dem Validierungdatum am {0,date} {0,time,full} revoziert.
+CertPathReviewer.revokedAfterValidation.details = Das Zertifikat wurde nach dem Validierungdatum am {0,date} {0,time,full} revoziert. Grund: {1}.
+
+# updated crl available
+# {0} date since when the update is available
+CertPathReviewer.crlUpdateAvailable.title = Zertifikatssperrlisten (CRL) Update erhältlich
+CertPathReviewer.crlUpdateAvailable.text = Ein Update für die Zertifikatssperrliste (CRL) für dieses Zertifikat ist erhältlich seit {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.summary = Ein Update für die Zertifikatssperrliste (CRL) für dieses Zertifikat ist erhältlich seit {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.details = Ein Update für die Zertifikatssperrliste (CRL) für dieses Zertifikat ist erhältlich seit {0,date} {0,time,full}.
+
+# crl distribution point url
+# {0} the crl distribution point url as String
+CertPathReviewer.crlDistPoint.title = CDP
+CertPathReviewer.crlDistPoint.text = Eine Zertifikatssperrliste (CRL) kann von {0} geladen werden.
+CertPathReviewer.crlDistPoint.summary = Eine Zertifikatssperrliste (CRL) kann von {0} geladen werden.
+CertPathReviewer.crlDistPoint.details = Eine Zertifikatssperrliste (CRL) kann von {0} geladen werden.
+
+# ocsp location
+# {0} the url on which the ocsp service can be found
+CertPathReviewer.ocspLocation.title = OCSP Server
+CertPathReviewer.ocspLocation.text = OCSP Server: {0}.
+CertPathReviewer.ocspLocation.summary = OCSP Server: {0}.
+CertPathReviewer.ocspLocation.details = OCSP Server: {0}.
+
+# unable to get crl from crl distribution point
+# {0} the url of the distribution point
+# {1} the message of the occurred exception
+# {2} the occurred exception
+# {3} the name of the exception
+CertPathReviewer.loadCrlDistPointError.title = Kann Zertifikatssperrliste (CRL) nicht von CDP laden
+CertPathReviewer.loadCrlDistPointError.text = Kann die Zertifikatssperrliste (CRL) von {0} nicht laden. Es gab eine {2}.
+CertPathReviewer.loadCrlDistPointError.summary = Kann die Zertifikatssperrliste (CRL) von {0} nicht laden. Es gab eine {2}.
+CertPathReviewer.loadCrlDistPointError.details = Kann die Zertifikatssperrliste (CRL) von {0} nicht laden. Es gab eine {2}. Grund: {1}.
+
+# no crl found in certstores
+# {0} the issuers which we searched for
+# {1} list of crl issuer names that are found in the certstores
+# {2} number of crls in the certstores
+CertPathReviewer.noCrlInCertstore.title = Keine Zertifikatssperrliste (CRL) im lokalen Speicher
+CertPathReviewer.noCrlInCertstore.text = Es wurde keine Zertifikatssperrliste (CRL) im lokalen Speicher gefunden.
+CertPathReviewer.noCrlInCertstore.summary = Es wurde keine Zertifikatssperrliste (CRL) im lokalen Speicher gefunden.
+CertPathReviewer.noCrlInCertstore.details = Es wurde keine Zertifikatssperrliste (CRL) für den Herausgeber {0} im lokalen Speicher gefunden. \
+Die {2} Zertifikatssperrlisten im lokalen Speicher wurden hearusgegeben von {1}.
+
+
+## check CRL exceptions
+
+# cannot extract issuer from certificate
+CertPathReviewer.crlIssuerException.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlIssuerException.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Kann den Herausgeber vom Zertifikat nicht extrahieren.
+CertPathReviewer.crlIssuerException.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Kann den Herausgeber vom Zertifikat nicht extrahieren.
+CertPathReviewer.crlIssuerException.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Kann den Herausgeber vom Zertifikat nicht extrahieren.
+
+# cannot extract crls
+# {0} message from the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.crlExtractionError.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlExtractionError.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab eine {2} beim laden der Zertifikatssperrliste (CRL) aus dem lokalen Speicher.
+CertPathReviewer.crlExtractionError.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab eine {2} beim laden der Zertifikatssperrliste (CRL) aus dem lokalen Speicher.
+CertPathReviewer.crlExtractionError.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab eine {2} beim laden der Zertifikatssperrliste (CRL) aus dem lokalen Speicher. Grund: {0}.
+
+# Issuer certificate key usage extension does not permit crl signing
+CertPathReviewer.noCrlSigningPermited.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.noCrlSigningPermited.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Das Herausgeber Zertifikat erlaubt keine Signieren von Zertifikatssperrlisten (CRL).
+CertPathReviewer.noCrlSigningPermited.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Das Herausgeber Zertifikat erlaubt keine Signieren von Zertifikatssperrlisten (CRL).
+CertPathReviewer.noCrlSigningPermited.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Das Herausgeber Zertifikat erlaubt keine Signieren von Zertifikatssperrlisten (CRL).
+
+# can not verify crl: issuer public key unknown
+CertPathReviewer.crlNoIssuerPublicKey.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlNoIssuerPublicKey.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Kann die Zertifikatssperrliste (CRL) nicht verifizieren. Der öffentliche Schlüssel des Herausgebers ist unbekannt.
+CertPathReviewer.crlNoIssuerPublicKey.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Kann die Zertifikatssperrliste (CRL) nicht verifizieren. Der öffentliche Schlüssel des Herausgebers ist unbekannt.
+CertPathReviewer.crlNoIssuerPublicKey.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Kann die Zertifikatssperrliste (CRL) nicht verifizieren. Der öffentliche Schlüssel des Herausgebers ist unbekannt.
+
+# crl verification failed
+CertPathReviewer.crlVerifyFailed.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlVerifyFailed.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Signatur der Zertifikatssperrliste (CRL) ist ungültig.
+CertPathReviewer.crlVerifyFailed.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Signatur der Zertifikatssperrliste (CRL) ist ungültig.
+CertPathReviewer.crlVerifyFailed.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Signatur der Zertifikatssperrliste (CRL) ist ungültig.
+
+# no valid CRL found
+CertPathReviewer.noValidCrlFound.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.noValidCrlFound.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: keine gültige Zertifikatssperrliste (CRL) gefunden.
+CertPathReviewer.noValidCrlFound.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: keine gültige Zertifikatssperrliste (CRL) gefunden.
+CertPathReviewer.noValidCrlFound.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: keine gültige Zertifikatssperrliste (CRL) gefunden.
+
+# No base CRL for delta CRL
+CertPathReviewer.noBaseCRL.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.noBaseCRL.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: keine Basis CRL für die Delta CRL gefunden.
+CertPathReviewer.noBaseCRL.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: keine Basis CRL für die Delta CRL gefunden.
+CertPathReviewer.noBaseCRL.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: keine Basis CRL für die Delta CRL gefunden.
+
+# certificate revoked
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.certRevoked.title = Zertifikat wurde revoziert
+CertPathReviewer.certRevoked.text = Das Zertifikat wurde am {0,date} {0,time,full} revoziert. Grund: {1}.
+CertPathReviewer.certRevoked.summary = Das Zertifikat wurde am {0,date} {0,time,full} revoziert.
+CertPathReviewer.certRevoked.details = Das Zertifikat wurde am {0,date} {0,time,full} revoziert. Grund: {1}.
+
+# error processing issuing distribution point extension
+CertPathReviewer.distrPtExtError.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.distrPtExtError.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Issuing Distribution Point Erweiterung.
+CertPathReviewer.distrPtExtError.summary = Fehler bei der Verarbeitung der Issuing Distribution Point Erweiterung.
+CertPathReviewer.distrPtExtError.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Issuing Distribution Point Erweiterung.
+
+# error processing crl distribution points extension
+CertPathReviewer.crlDistPtExtError.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlDistPtExtError.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der CRL Distribution Points Erweiterung.
+CertPathReviewer.crlDistPtExtError.summary = Fehler bei der Verarbeitung der CRL Distribution Points Erweiterung.
+CertPathReviewer.crlDistPtExtError.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der CRL Distribution Points Erweiterung.
+
+# error processing the authority info access extension
+CertPathReviewer.crlAuthInfoAccError.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlAuthInfoAccError.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Authority Info Access Erweiterung.
+CertPathReviewer.crlAuthInfoAccError.summary = Fehler bei der Verarbeitung der Authority Info Access Erweiterung.
+CertPathReviewer.crlAuthInfoAccError.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Authority Info Access Erweiterung.
+
+# error processing delta crl indicator extension
+CertPathReviewer.deltaCrlExtError.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.deltaCrlExtError.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Delta CRL Indicator Erweiterung.
+CertPathReviewer.deltaCrlExtError.summary = Fehler bei der Verarbeitung der Delta CRL Indicator Erweiterung.
+CertPathReviewer.deltaCrlExtError.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der Delta CRL Indicator Erweiterung.
+
+# error porcessing crl number extension
+CertPathReviewer.crlNbrExtError.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlNbrExtError.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der CRL Number Erweiterung.
+CertPathReviewer.crlNbrExtError.summary = Fehler bei der Verarbeitung der CRL Number Erweiterung.
+CertPathReviewer.crlNbrExtError.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der CRL Number Erweiterung.
+
+# error processing crl reason code extension
+CertPathReviewer.crlReasonExtError.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlReasonExtError.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der CRL Reason Code Erweiterung.
+CertPathReviewer.crlReasonExtError.summary = Fehler bei der Verarbeitung der CRL Reason Code Erweiterung.
+CertPathReviewer.crlReasonExtError.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der CRL Reason Code Erweiterung.
+
+# error processing basic constraints extension
+CertPathReviewer.crlBCExtError.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlBCExtError.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der CRL Reason Code Erweiterung.
+CertPathReviewer.crlBCExtError.summary = Fehler bei der Verarbeitung der CRL Reason Code Erweiterung.
+CertPathReviewer.crlBCExtError.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Es gab einen Fehler bei der Verarbeitung der CRL Reason Code Erweiterung.
+
+# CA Cert CRL only contains user certificates
+CertPathReviewer.crlOnlyUserCert.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlOnlyUserCert.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur User Zertifikate.
+CertPathReviewer.crlOnlyUserCert.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur User Zertifikate.
+CertPathReviewer.crlOnlyUserCert.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur User Zertifikate.
+
+# End CRL only contains CA certificates
+CertPathReviewer.crlOnlyCaCert.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlOnlyCaCert.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur CA Zertifikate.
+CertPathReviewer.crlOnlyCaCert.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur CA Zertifikate.
+CertPathReviewer.crlOnlyCaCert.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur CA Zertifikate.
+
+# onlyContainsAttributeCerts boolean is asserted
+CertPathReviewer.crlOnlyAttrCert.title = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen
+CertPathReviewer.crlOnlyAttrCert.text = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur Attribut Zertifikate.
+CertPathReviewer.crlOnlyAttrCert.summary = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur Attribut Zertifikate.
+CertPathReviewer.crlOnlyAttrCert.details = Prüfung der Zertifikatssperrliste (CRL) fehlgeschlagen: Die Zertifikatssperrliste (CRL) enthält nur Attribut Zertifikate.
+
+
+## QcStatement notifications
+
+# unkown statement
+# {0} statement OID
+# {1} statement as ANS1Sequence
+CertPathReviewer.QcUnknownStatement.title = Unbekanntes Statement in der QcStatement Erweiterung
+CertPathReviewer.QcUnknownStatement.text = Unbekanntes Statement in der QcStatement Erweiterung: OID = {0}
+CertPathReviewer.QcUnknownStatement.summary = Unbekanntes Statement in der QcStatement Erweiterung: OID = {0}
+CertPathReviewer.QcUnknownStatement.details = Unbekanntes Statement in der QcStatement Erweiterung: OID = {0}, statement = {1}
+
+# QcLimitValue Alpha currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueAlpha.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueAlpha.text = Dieses Zertifikat hat ein Wertlimite von {1,number, ###,###,###,##0.00#} {0} für Transaktionen.
+CertPathReviewer.QcLimitValueAlpha.summary = Wertlimite von {1,number, ###,###,###,##0.00#} {0} für Transaktionen.
+CertPathReviewer.QcLimitValueAlpha.details = Dieses Zertifikat hat eine Wertlimite für Transaktionen für welche\
+ das Zertifikat genutzt werden kann, gemäss der Richtlinie 1999/93/EG des Europäischen Parlaments und\
+ des Rates über gemeinschaftliche Rahmenbedingungen für elektronische Signaturen und gemäss der Umsetzung der\
+ Richtlinie im Land, das im Herausgeber dieses Zertifikats angegeben ist. Die Limite für diese Zertifikat ist {1,number, ###,###,###,##0.00#} {0}.
+
+# QcLimitValue Numeric currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueNum.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueNum.text = Dieses Zertifikat hat eine Wertlimite für Transaktionen von {1,number, ###,###,###,##0.00#} der Währung {0} (Siehe RFC 4217 für Währungscodes).
+CertPathReviewer.QcLimitValueNum.summary = Wertlimite für Transaktionen von {1,number, ###,###,###,##0.00#} der Währung {0} (Siehe RFC 4217 für Währungscodes).
+CertPathReviewer.QcLimitValueNum.details = Dieses Zertifikat hat eine Wertlimite für Transaktionen für welche\
+ das Zertifikat genutzt werden kann, gemäss der Richtlinie 1999/93/EG des Europäischen Parlaments und\
+ des Rates über gemeinschaftliche Rahmenbedingungen für elektronische Signaturen und gemäss der Umsetzung der\
+ Richtlinie im Land, das im Herausgeber dieses Zertifikats angegeben ist. Die Limite für diese Zertifikat ist {1,number, ###,###,###,##0.00#} der Währung {0} (Siehe RFC 4217 für Währungscodes).
+
+# QcSSCD
+CertPathReviewer.QcSSCD.title = QcSSCD Statement
+CertPathReviewer.QcSSCD.text = (SSCD) Der Herausgeber macht geltend, dass der Private Schlüssel, der mit diesem Zertifikat verbunden ist, nach den Anforderungen die im Anhang III der Richtlinie 1999/93/EG des Europäischen Parlaments und des Rates über gemeinschaftliche Rahmenbedingungen für elektronische Signaturen geschützt ist.
+CertPathReviewer.QcSSCD.summary = (SSCD) Der Herausgeber macht geltend, dass der Private Schlüssel, der mit diesem Zertifikat verbunden ist, nach den Anforderungen die im Anhang III der Richtlinie 1999/93/EG des Europäischen Parlaments und des Rates über gemeinschaftliche Rahmenbedingungen für elektronische Signaturen geschützt ist.
+CertPathReviewer.QcSSCD.details = (SSCD) Der Herausgeber macht geltend, dass der Private Schlüssel, der mit diesem Zertifikat verbunden ist, nach den Anforderungen die im Anhang III der Richtlinie 1999/93/EG des Europäischen Parlaments und des Rates über gemeinschaftliche Rahmenbedingungen für elektronische Signaturen geschützt ist.
+
+# QcEuCompliance
+CertPathReviewer.QcEuCompliance.title = Qualifiziertes Zertifikat
+CertPathReviewer.QcEuCompliance.text = Dieses Zertifikat wurde als Qualifiziertes Zertifikat herausgegeben gemäss Anhang I und II der Richtlinie 1999/93/EG des Europäischen Parlaments und des Rates über gemeinschaftliche Rahmenbedingungen für elektronische Signaturen und gemäss der Umsetzung der Richtlinie im Land, das im Herausgeber dieses Zertifikats angegeben ist.
+CertPathReviewer.QcEuCompliance.summary = Dieses Zertifikat wurde als Qualifiziertes Zertifikat herausgegeben gemäss Anhang I und II der Richtlinie 1999/93/EG des Europäischen Parlaments und des Rates über gemeinschaftliche Rahmenbedingungen für elektronische Signaturen und gemäss der Umsetzung der Richtlinie in dem Land, das im Herausgeber dieses Zertifikats angegeben ist.
+CertPathReviewer.QcEuCompliance.details = Dieses Zertifikat wurde als Qualifiziertes Zertifikat herausgegeben gemäss Anhang I und II der Richtlinie 1999/93/EG des Europäischen Parlaments und des Rates über gemeinschaftliche Rahmenbedingungen für elektronische Signaturen und gemäss der Umsetzung der Richtlinie in dem Land, das im Herausgeber dieses Zertifikats angegeben ist.
+
+## QcStatement errors
+
+# error processing the QcStatement extension
+CertPathReviewer.QcStatementExtError.title = Fehler bei der Verarbeitung der QcStatement Erweiterung
+CertPathReviewer.QcStatementExtError.text = Fehler bei der Verarbeitung der QcStatement Erweiterung.
+CertPathReviewer.QcStatementExtError.summary = Fehler bei der Verarbeitung der QcStatement Erweiterung.
+CertPathReviewer.QcStatementExtError.details = Fehler bei der Verarbeitung der QcStatement Erweiterung.
+
+## unknown/generic errors
+CertPathReviewer.unknown.title = Unbekannter Fehler
+CertPathReviewer.unknown.text = Unbekannter Fehler {0}
+CertPathReviewer.unknown.summary = Unbekannter Fehler
+CertPathReviewer.unknown.details = Unbekannter Fehler {0}
+
+#
+# crl reasons
+#
+unspecified = Nicht spezifiziert
+keyCompromise = Schlüssel Kompromittierung
+cACompromise = CA Kompromittierung
+affiliationChanged = Veränderte Zugehörigkeit
+superseded = Ersetzt
+cessationOfOperation = Einstellen der Tätigkeiten
+certificateHold = Zertifikat vorübergehend gesperrt
+unknown = Unbekannt
+removeFromCRL = Entferne von der CRL
+privilegeWithdrawn = Zurückgezogene Rechte
+aACompromise = AA Kompromittierung
+
+#
+#
+#
+missingIssuer = The missing certificate was issued by
+missingSerial = with the serial number